Go Functions

Ma Mahalakshmi V Updated 04 Nov 2026
6 min read

Go Functions

A function is a named, reusable block of code that performs a specific task. Functions let you organize a program into logical pieces, avoid repeating the same code in multiple places, and make programs easier to read, test, and maintain.

A function never runs on its own — it executes only when something explicitly calls it.

Why Use Functions?

  • Promote code reuse — write the logic once, call it wherever it's needed.
  • Improve program structure by breaking a large problem into smaller, named pieces.
  • Simplify debugging — a bug is easier to isolate when logic lives in one clearly named place.
  • Reduce duplication, which reduces the number of places a future change has to be made.

Defining a Function

func functionName() {
    // code to execute
}
  • func declares a function.
  • The function body sits inside {} and runs top to bottom when the function is called.

Calling a Function

A function only runs when its name is followed by parentheses:

package main

import "fmt"

// function definition
func displayWelcome() {
    fmt.Println("Welcome to Go programming!")
}

func main() {
    displayWelcome() // function call
}

Expected output:

Welcome to Go programming!

Calling a Function Multiple Times

package main

import "fmt"

func printSeparator() {
    fmt.Println("-----------")
}

func main() {
    printSeparator()
    fmt.Println("Section 1")

    printSeparator()
    fmt.Println("Section 2")

    printSeparator()
}

Expected output:

-----------
Section 1
-----------
Section 2
-----------

Function Parameters and Arguments

Functions can accept input values, called parameters, which act as local variables inside the function body. This is what makes a function flexible and reusable instead of hard-coded to one specific value.

func FunctionName(param1 type, param2 type, param3 type) {
    // code to execute
}

Parameters vs. arguments — a distinction worth being precise about:

  • A parameter is the variable named in the function's declaration (e.g., name in func greetUser(name string)).
  • An argument is the actual value supplied when the function is called (e.g., "Aarav" in greetUser("Aarav")).

Example: Single Parameter

package main

import "fmt"

func greetUser(name string) {
    fmt.Println("Welcome,", name+"!")
}

func main() {
    greetUser("Aarav")
    greetUser("Meera")
    greetUser("Rohan")
}

Expected output:

Welcome, Aarav!
Welcome, Meera!
Welcome, Rohan!

Example: Multiple Parameters

package main

import "fmt"

func displayProfile(name string, age int) {
    fmt.Println(name, "is", age, "years old.")
}

func main() {
    displayProfile("Arjun", 21)
    displayProfile("Sneha", 25)
    displayProfile("Kiran", 30)
}

Expected output:

Arjun is 21 years old.
Sneha is 25 years old.
Kiran is 30 years old.

Tip: when consecutive parameters share the same type, Go lets you omit the type on all but the last: func displayProfile(name string, age int) can also be written with more parameters as func f(a, b string, c int).

Return Values

A function can send a value back to its caller. To do this, specify a return type in the function signature and use the return keyword.

func FunctionName(param1 type, param2 type) returnType {
    // code to execute
    return value
}

Example: Returning a Single Value

package main

import "fmt"

func multiply(a int, b int) int {
    return a * b
}

func main() {
    result := multiply(4, 5)
    fmt.Println("Product:", result)
}

Expected output:

Product: 20

Named Return Values

Go allows you to name the return value directly in the function signature. Once named, that variable is automatically declared inside the function, and a bare return (with no value after it) returns whatever it currently holds:

package main

import "fmt"

func calculateTotal(price int, quantity int) (total int) {
    total = price * quantity
    return // returns the current value of 'total'
}

func main() {
    fmt.Println(calculateTotal(150, 3))
}

An explicit return total is equally valid and, in most style guides, considered clearer for anything beyond a very short function — the implicit "naked" return is best reserved for small functions where the intent stays obvious at a glance.

Storing a Return Value

package main

import "fmt"

func square(n int) int {
    return n * n
}

func main() {
    value := square(6)
    fmt.Println("Square:", value)
}

Multiple Return Values

One of Go's most distinctive features is that a function can return more than one value. This is used constantly throughout the standard library — most famously for returning a result and an error from the same call.

package main

import "fmt"

// Function returning multiple values
func getUserInfo(id int) (string, int) {
    name := "User"
    age := 20 + id
    return name, age
}

func main() {
    name, age := getUserInfo(2)
    fmt.Println(name, age)
}

Expected output:

User 22

Ignoring Unwanted Return Values

If you don't need every value a function returns, discard the ones you don't want with the blank identifier _:

// Ignore the first value
_, age := getUserInfo(3)
fmt.Println("Age:", age)

// Ignore the second value
name, _ := getUserInfo(3)
fmt.Println("Name:", name)

Where this leads next: the two-value return pattern (value, err := someFunction()) is the foundation of Go's approach to error handling, which you'll encounter throughout the standard library — for example, file, err := os.Open("data.txt"). This series covers error handling in a dedicated lesson once functions and structs are established.

Recursion

A function that calls itself is called recursive. Recursion breaks a problem down into smaller versions of the same problem, repeating until it reaches a base case — a condition simple enough to answer directly, without another recursive call.

Without a correctly defined base case, a recursive function calls itself indefinitely, which eventually crashes the program with a stack overflow. A well-formed recursive function always has two parts:

  • Base case — stops the recursion.
  • Recursive case — calls the function again, with input that moves it closer to the base case.

Example: Counting with Recursion

package main

import "fmt"

func printNumbers(n int) {
    if n > 5 {
        return // base case
    }

    fmt.Println(n)
    printNumbers(n + 1) // recursive case
}

func main() {
    printNumbers(1)
}

Expected output:

1
2
3
4
5

Example: Factorial

package main

import "fmt"

func factorial(n int) int {
    if n == 0 {
        return 1 // base case
    }
    return n * factorial(n-1) // recursive case
}

func main() {
    result := factorial(5)
    fmt.Println("Factorial:", result)
}

Expected output:

Factorial: 120

When to Use Recursion

Recursion is a natural fit for:

  • Problems that break down into smaller versions of themselves (factorial, Fibonacci).
  • Traversing trees and graphs, where each node's children are processed the same way as the node itself.
  • Divide-and-conquer algorithms.

Common mistake: forgetting the base case, or writing a base case that the recursive calls never actually reach (for example, decrementing n when the base case checks for n == 0 but the input starts negative) — either mistake produces infinite recursion and a runtime crash rather than a clean error message.

0 Comments

Reviewed before they appear

No comments yet.

Go
Ask about this post
AI Ask about this post

Ask questions about Go Functions and get answers drawn from it.

Signed-in readers only.