Skip to main content

Functions

Introduction​

Functions in Go are declared with the func keyword. Unlike Python, Go requires you to explicitly declare the types of all parameters and return values. If a function returns multiple values — a common pattern in Go — all return types must be listed.

Go does not have optional parameters or keyword arguments as Python does. Instead, Go programmers use structs, variadic parameters, or separate functions when flexibility is needed.

One of Go's most distinctive patterns is returning errors as values rather than throwing exceptions. A Go function that might fail typically returns (result, error). The caller is expected to check the error immediately. This makes error handling explicit and visible, unlike Python's try/except which can be placed far from where the error occurs.

GitHub Copilot tip: Paste any Python function into Copilot Chat and ask: Convert this Python function to Go, explaining the differences. This is a great way to see the translation of patterns you already know.


Concepts​

Function declaration​

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

// Parameters of the same type can share a type declaration
func multiply(a, b int) int {
return a * b
}

Multiple return values​

func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("cannot divide by zero")
}
return a / b, nil
}

Variadic functions​

func sum(numbers ...int) int {
total := 0
for _, n := range numbers {
total += n
}
return total
}
// Called as: sum(1, 2, 3, 4, 5)

Named return values​

func minMax(nums []int) (min, max int) {
min, max = nums[0], nums[0]
for _, n := range nums {
if n < min { min = n }
if n > max { max = n }
}
return // "naked return" — returns the named values
}

Examples​

package main

import (
"fmt"
"errors"
)

func greet(name string) string {
return fmt.Sprintf("Hello, %s!", name)
}

func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}

func sum(numbers ...int) int {
total := 0
for _, n := range numbers {
total += n
}
return total
}

func main() {
fmt.Println(greet("Alice"))

result, err := divide(10, 3)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Printf("10 / 3 = %.4f\n", result)
}

_, err = divide(5, 0)
if err != nil {
fmt.Println("Error:", err)
}

fmt.Println("Sum:", sum(1, 2, 3, 4, 5))
}

Challenges​

1. Write a basic function​

  • Write a function square(n int) int that returns the square of a number.
  • Call it from main with a few different values and print the results.
💡 Show Answer
package main

import "fmt"

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

func main() {
fmt.Println(square(3)) // 9
fmt.Println(square(7)) // 49
fmt.Println(square(12)) // 144
}

2. Function with multiple parameters​

  • Write a function fullName(first, last string) string that returns the full name as a single string.
  • Call it and print the result.
💡 Show Answer
package main

import "fmt"

func fullName(first, last string) string {
return first + " " + last
}

func main() {
fmt.Println(fullName("Alice", "Smith"))
fmt.Println(fullName("Bob", "Jones"))
}

Note: first, last string is shorthand for first string, last string when both parameters share the same type.


3. Multiple return values​

  • Write a function swap(a, b int) (int, int) that returns the two values swapped.
  • Call it and print both return values.
💡 Show Answer
package main

import "fmt"

func swap(a, b int) (int, int) {
return b, a
}

func main() {
x, y := swap(10, 20)
fmt.Println(x, y) // 20 10
}

4. Error handling pattern​

  • Write a function safeDivide(a, b int) (int, error) that returns an error if b is zero.
  • In main, call it twice — once with a valid divisor and once with zero. Handle both cases.
💡 Show Answer
package main

import (
"errors"
"fmt"
)

func safeDivide(a, b int) (int, error) {
if b == 0 {
return 0, errors.New("cannot divide by zero")
}
return a / b, nil
}

func main() {
result, err := safeDivide(10, 2)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Println("Result:", result)
}

_, err = safeDivide(5, 0)
if err != nil {
fmt.Println("Error:", err)
}
}

Ask Copilot: How does Go's error-as-value pattern compare to Python's try/except?


5. Variadic function​

  • Write a variadic function average(nums ...float64) float64 that returns the average of any number of floats.
  • Test it with different numbers of arguments.
💡 Show Answer
package main

import "fmt"

func average(nums ...float64) float64 {
if len(nums) == 0 {
return 0
}
total := 0.0
for _, n := range nums {
total += n
}
return total / float64(len(nums))
}

func main() {
fmt.Printf("%.2f\n", average(10, 20, 30)) // 20.00
fmt.Printf("%.2f\n", average(1, 2, 3, 4, 5)) // 3.00
fmt.Printf("%.2f\n", average(100)) // 100.00
}

6. Functions as values​

  • Assign a function to a variable and call it through that variable.
  • Ask Copilot: Are Go functions first-class values like Python functions?
💡 Show Answer
package main

import "fmt"

func main() {
// Assign a function to a variable
double := func(n int) int {
return n * 2
}

fmt.Println(double(5)) // 10
fmt.Println(double(21)) // 42

// Pass a function as an argument
apply := func(n int, f func(int) int) int {
return f(n)
}
fmt.Println(apply(7, double)) // 14
}

Yes — Go functions are first-class values. They can be assigned to variables, passed as arguments, and returned from other functions, just like in Python.


7. Convert a Python function to Go​

  • Here is a Python function:
def celsius_to_fahrenheit(c):
return (c * 9 / 5) + 32
  • Ask Copilot to convert it to Go, then implement it yourself first and compare.
💡 Show Answer
package main

import "fmt"

func celsiusToFahrenheit(c float64) float64 {
return (c*9/5) + 32
}

func main() {
fmt.Printf("0°C = %.1f°F\n", celsiusToFahrenheit(0)) // 32.0°F
fmt.Printf("100°C = %.1f°F\n", celsiusToFahrenheit(100)) // 212.0°F
fmt.Printf("37°C = %.1f°F\n", celsiusToFahrenheit(37)) // 98.6°F
}

Key differences: Go uses camelCase for function names (celsiusToFahrenheit), requires explicit parameter and return types, and requires the float64(...) conversion if the input were an int.


8. Recursive function​

  • Write a recursive function factorial(n int) int that calculates n!
  • Test it for n = 0 through 10.
💡 Show Answer
package main

import "fmt"

func factorial(n int) int {
if n <= 1 {
return 1
}
return n * factorial(n-1)
}

func main() {
for i := 0; i <= 10; i++ {
fmt.Printf("%2d! = %d\n", i, factorial(i))
}
}