Go Functions

A function in Go is a named, reusable block of code that performs a specific task. Functions can receive input through parameters, return one or more values, and be called from other parts of a program.

This tutorial explains how to declare and call Go functions, pass arguments, return values, use variadic parameters, create anonymous functions and closures, and distinguish functions from methods with receivers.


Go Function Declaration Syntax

The basic syntax for defining a function in Go is as follows:

</>
Copy
func functionName(parameters) returnType {
    // Function body
}

A Go function declaration can contain the following parts:

  • func: The keyword that begins a function declaration.
  • Function name: The identifier used to call the function.
  • Parameters: Typed input variables placed inside parentheses. Parameters are optional.
  • Return type: The type of the value returned to the caller. It is omitted when the function returns nothing.
  • Function body: Statements enclosed in braces that run when the function is called.

Calling a Go Function

Declare a function at package scope and call it by writing its name followed by parentheses. Arguments supplied by the caller are assigned to the function’s parameters in the same order.

</>
Copy
package main

import "fmt"

func displayMessage(message string) {
    fmt.Println(message)
}

func main() {
    displayMessage("Learning Go functions")
}

Output

Learning Go functions

Common Types of Functions in Go

Go functions may have parameters, return values, both, or neither. The following examples show the common declaration patterns.


1 Go Function Without Parameters or a Return Value

This function performs an action but does not receive input or return a result:

</>
Copy
package main

import "fmt"

// Function without parameters and return value
func greet() {
    fmt.Println("Hello, World!")
}

func main() {
    greet() // Call the function
}

How the greet Function Works

  1. Declare the function: greet has empty parentheses because it accepts no parameters.
  2. Run its statements: The body prints a message with fmt.Println.
  3. Call the function: greet() transfers execution to the function body.

greet Function Output


2 Go Function With Parameters

Parameters let a function receive values from its caller. Each parameter has a name and a type:

</>
Copy
package main

import "fmt"

// Function with parameters
func add(a int, b int) {
    fmt.Println("Sum:", a+b)
}

func main() {
    add(10, 20) // Call the function with arguments
}

How Function Parameters Receive Arguments

  1. Declare parameters: The function add declares a and b as parameters of type int.
  2. Pass arguments: In add(10, 20), 10 is assigned to a and 20 to b.
  3. Use parameter values: The function adds the values and prints the result.

add Function Output

Shortened Parameter Declarations of the Same Type

When consecutive parameters have the same type, Go permits the type to be written once after the final parameter name.

</>
Copy
func add(a, b int) {
    // a and b are both int values
}

This declaration is equivalent to func add(a int, b int).


3 Go Function With a Return Value

A function can calculate a value and return it to the calling code:

</>
Copy
package main

import "fmt"

// Function with return value
func multiply(a int, b int) int {
    return a * b
}

func main() {
    result := multiply(5, 4) // Call the function and store the result
    fmt.Println("Product:", result)
}

How a Go Function Returns a Value

  1. Declare the result type: The int after the parameter list specifies that multiply returns an integer.
  2. Return the result: return a * b sends the calculated product back to the caller.
  3. Store the returned value: The caller assigns the returned integer to result.

multiply Function Output


4 Go Function With Multiple Return Values

Go functions can return multiple values in a single call. This is commonly used when a calculation produces related results or when a function returns both a value and an error.

</>
Copy
package main

import "fmt"

// Function with multiple return values
func divide(a int, b int) (int, int) {
    return a / b, a % b // Return quotient and remainder
}

func main() {
    quotient, remainder := divide(10, 3) // Call the function and capture results
    fmt.Println("Quotient:", quotient)
    fmt.Println("Remainder:", remainder)
}

How Multiple Return Values Are Collected

  1. Declare result types: (int, int) indicates that the function returns two integers.
  2. Return values in order: The quotient is returned first and the remainder second.
  3. Assign both results: The caller receives the values in quotient and remainder in the corresponding order.

divide Function Output

Ignoring an Unneeded Return Value

Use the blank identifier _ when a function returns a value that the caller does not need.

</>
Copy
quotient, _ := divide(10, 3)
fmt.Println(quotient)

Go does not allow a declared local variable to remain unused, so the blank identifier explicitly discards the second result.


5 Variadic Function in Go

A variadic function accepts zero or more arguments for its final parameter. Place ... before the parameter type to declare it:

</>
Copy
package main

import "fmt"

// Variadic function
func sum(nums ...int) int {
    total := 0
    for _, num := range nums {
        total += num
    }
    return total
}

func main() {
    fmt.Println("Sum:", sum(1, 2, 3, 4, 5)) // Call with multiple arguments
}

How the Variadic Parameter Works

  1. Declare a variadic parameter: nums ...int accepts any number of integer arguments.
  2. Receive a slice: Inside the function, nums behaves as a value of type []int.
  3. Process every argument: The range loop visits each supplied integer and adds it to total.

Variadic sum Function Output

Passing a Slice to a Variadic Function

To pass an existing slice as the variadic arguments, append ... to the slice expression.

</>
Copy
values := []int{4, 8, 12}
result := sum(values...)
fmt.Println(result)

Output

24

A function can have other parameters before a variadic parameter, but the variadic parameter must be last.


Named Return Values in Go Functions

Go permits names to be assigned to return values in the function signature. These names act as variables within the function body.

</>
Copy
package main

import "fmt"

func rectangle(size int) (width int, height int) {
    width = size * 2
    height = size
    return
}

func main() {
    w, h := rectangle(5)
    fmt.Println("Width:", w)
    fmt.Println("Height:", h)
}

How a Bare Return Uses Named Results

The final return statement does not list expressions because width and height are named result variables. This form is called a bare return.

Named results can document what each returned value represents, but explicit return expressions are often clearer in longer functions.

Output

Width: 10
Height: 5

Functions as Values and Function Types in Go

Functions are values in Go. A function can be assigned to a variable, passed to another function, or returned from a function. The variable’s function type must match the parameter and result types of the assigned function.

</>
Copy
package main

import "fmt"

func subtract(a, b int) int {
    return a - b
}

func main() {
    operation := subtract
    result := operation(10, 4)
    fmt.Println(result)
}

In this example, operation has the function type func(int, int) int.

Passing a Function as an Argument

A higher-order function accepts another function as an argument or returns a function as its result.

</>
Copy
package main

import "fmt"

func calculate(a, b int, operation func(int, int) int) int {
    return operation(a, b)
}

func addValues(a, b int) int {
    return a + b
}

func main() {
    result := calculate(7, 3, addValues)
    fmt.Println(result)
}

Output

10

Anonymous Functions and Closures in Go

An anonymous function is a function literal without a declared name. It can be assigned to a variable or invoked immediately.

</>
Copy
package main

import "fmt"

func main() {
    square := func(number int) int {
        return number * number
    }

    fmt.Println(square(6))
}

Go Closure That Retains Enclosing Variables

A closure is a function value that refers to variables from its surrounding scope. The function retains access to those variables while the closure remains reachable.

</>
Copy
package main

import "fmt"

func counter() func() int {
    count := 0

    return func() int {
        count++
        return count
    }
}

func main() {
    next := counter()

    fmt.Println(next())
    fmt.Println(next())
    fmt.Println(next())
}

Closure Output

1
2
3

Each call to next updates the same captured count variable. Calling counter() again would create a separate closure with its own count.


Recursive Functions in Go

A recursive function calls itself. It must include a condition that stops further calls; otherwise, recursion continues until the program exhausts the available stack.

</>
Copy
package main

import "fmt"

func factorial(number int) int {
    if number <= 1 {
        return 1
    }

    return number * factorial(number-1)
}

func main() {
    fmt.Println(factorial(5))
}

How the Recursive Factorial Function Stops

The condition number <= 1 is the base case. For factorial(5), the function evaluates 5 × 4 × 3 × 2 × 1 and returns 120.

Output

120

Go Functions Versus Methods With Receivers

A regular function is declared with a name immediately after func. A method includes a receiver parameter between func and the method name. The receiver associates the method with a defined type.

</>
Copy
package main

import "fmt"

type Rectangle struct {
    Width  float64
    Height float64
}

func area(width, height float64) float64 {
    return width * height
}

func (rectangle Rectangle) Area() float64 {
    return rectangle.Width * rectangle.Height
}

func main() {
    shape := Rectangle{Width: 6, Height: 4}

    fmt.Println(area(shape.Width, shape.Height))
    fmt.Println(shape.Area())
}

Reading the Method Receiver Syntax

  • func area(...) declares a regular package-level function.
  • func (rectangle Rectangle) Area() declares a method with a value receiver of type Rectangle.
  • The method is called with selector syntax: shape.Area().
  • A pointer receiver, such as func (rectangle *Rectangle) Resize(), is commonly used when a method must modify the receiver or avoid copying a large value.

The receiver is not a special form of return value. It is the parameter that identifies the type to which the method belongs.


How Go Passes Function Arguments

Go passes arguments by value. A function receives a copy of each argument value. Assigning a new value to a parameter does not replace the caller’s original variable.

</>
Copy
package main

import "fmt"

func changeValue(number int) {
    number = 100
}

func main() {
    value := 10
    changeValue(value)
    fmt.Println(value)
}

Output

10

Using a Pointer Parameter to Modify a Variable

Pass a pointer when a function needs to update a caller-owned variable.

</>
Copy
package main

import "fmt"

func changeValue(number *int) {
    *number = 100
}

func main() {
    value := 10
    changeValue(&value)
    fmt.Println(value)
}

Output

100

The pointer itself is still passed by value, but it refers to the original variable, allowing the function to update the value stored at that address.


Function Naming and Export Rules in Go

  • A function name must be a valid Go identifier and cannot be a keyword.
  • Names are case-sensitive, so calculate and Calculate are different identifiers.
  • A name beginning with an uppercase Unicode letter is exported from its package.
  • A lowercase function name is accessible only from within the same package.
  • Go code commonly uses mixedCaps or MixedCaps rather than underscores in function names.

For example, ParseFile may be called by another package when its containing package is imported, while parseFile remains unexported.


Common Go Function Mistakes

  • Placing the return type before the function name: Go places result types after the parameter list.
  • Using arguments with incompatible types: The supplied values must be assignable to the declared parameter types.
  • Forgetting to use a returned value: Capture the result or explicitly discard it with _ when multiple values are returned.
  • Putting a variadic parameter before another parameter: A variadic parameter must be the final parameter.
  • Expecting an ordinary value parameter to modify the caller’s variable: Use a pointer or return the modified value.
  • Writing recursion without a reachable base case: Every recursive path must eventually stop.
  • Confusing a method receiver with a parameter list: The receiver appears before the method name and associates the method with a type.

Frequently Asked Questions About Go Functions

What does func mean in Go?

func is the Go keyword used to declare a function, method, or function literal. A named function uses the form func name(...), while a method places a receiver between func and the method name.

Can a Go function return more than one value?

Yes. Place the result types in parentheses, such as (int, error), and return the corresponding values in the same order. Multiple returns are commonly used to return a result together with an error.

What is the difference between a Go function and a method?

A function is declared at package scope without a receiver. A method has a receiver associated with a defined type and is commonly called through selector syntax, such as value.Method().

Can a Go function be stored in a variable?

Yes. Functions are values in Go. A function can be assigned to a variable when its signature matches the variable’s function type. It can also be passed as an argument or returned from another function.

Does Go support optional function parameters?

Go does not provide optional parameters or default argument values in ordinary function declarations. Common alternatives include separate functions, configuration structs, or a variadic parameter when accepting zero or more values of one type is appropriate.


Go Functions Editorial QA Checklist

  • Verify that each function signature places parameters before result types.
  • Confirm that every returned expression is assignable to the declared result type.
  • Check that multiple return values are assigned or discarded in the correct order.
  • Confirm that every variadic parameter is last and that slice expansion uses slice....
  • Check that recursive examples contain a reachable base case.
  • Verify that method examples place the receiver before the method name and use an appropriate value or pointer receiver.
  • Run each complete example with go run and compare its output with the tutorial.

Go Function Rules to Remember

  • Functions and methods begin with the func keyword.
  • Parameters and results are statically typed.
  • A function may return no value, one value, or multiple values.
  • Consecutive parameters of the same type may share one type declaration.
  • Variadic parameters receive their arguments as a slice and must appear last.
  • Functions can be assigned, passed, and returned as values.
  • Closures retain access to variables from their surrounding scope.
  • Arguments are passed by value; use pointers when direct mutation is required.
  • Function names beginning with an uppercase letter are exported from their package.