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) intthat returns the square of a number. - Call it from
mainwith 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) stringthat 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 ifbis 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) float64that 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) intthat 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))
}
}