Functions
Learn Go's function declaration syntax, parameters, return types, and named return values.
Introduction
Functions are the primary way you organize behavior in Go. You've already used functions like fmt.Println and main itself — now it's time to learn how to write your own. Go's function syntax is explicit and consistent: parameter types, return types, and behavior are all clearly declared up front.
- The syntax for declaring a function in Go.
- How to define parameters, including grouping same-typed parameters.
- How to specify return types.
- What named return values are and when they help.
- How functions can be treated as values.
Declaring a Function
A function is declared with the func keyword, a name, a parameter list in parentheses, an optional return type, and a body in curly braces.
package main
import "fmt"
func greet(name string) string { return "Hello, " + name + "!"}
func main() { message := greet("World") fmt.Println(message)}Click Run to see what this code prints.
Parameters
Each parameter is written as name type. When several consecutive parameters share the same type, you can omit the type on all but the last one, which keeps signatures compact.
package main
import "fmt"
// x and y share type int, so it's only written once.func add(x, y int) int { return x + y}
func describePerson(name string, age int, active bool) string { status := "inactive" if active { status = "active" } return fmt.Sprintf("%s is %d years old and %s", name, age, status)}
func main() { fmt.Println(add(3, 4)) fmt.Println(describePerson("Maria", 29, true))}Click Run to see what this code prints.
Return Types
A function's return type appears after the parameter list. Go functions can return multiple values by wrapping the return types in parentheses — a feature covered in depth in the next lesson. For now, focus on single-value returns.
package main
import "fmt"
func square(n int) int { return n * n}
func isEven(n int) bool { return n%2 == 0}
func main() { fmt.Println(square(6)) fmt.Println(isEven(6)) fmt.Println(isEven(7))}Click Run to see what this code prints.
Named Return Values
Go lets you name your return values in the function signature. A named return value is automatically declared as a variable inside the function, initialized to its zero value, and returned automatically if you use a bare return statement with no arguments. This can make short functions more readable, especially when the return value's meaning isn't obvious from the type alone.
package main
import "fmt"
func divide(dividend, divisor float64) (result float64, err error) { if divisor == 0 { err = fmt.Errorf("cannot divide %.2f by zero", dividend) return // returns the zero value 0 for result, and err } result = dividend / divisor return // returns result and nil err}
func main() { res, err := divide(10, 2) fmt.Println(res, err)
res, err = divide(5, 0) fmt.Println(res, err)}Click Run to see what this code prints.
Named returns are great for documenting intent in short functions, but in longer functions a bare "return" can obscure exactly what's being returned. Many style guides recommend using explicit return values (return result, err) even when the names are declared, reserving bare returns for short, simple functions.
Functions as Values
In Go, functions are first-class values: you can assign a function to a variable, pass it as an argument, or return it from another function. This is the foundation for the closures you'll explore in a later lesson.
package main
import "fmt"
func multiply(a, b int) int { return a * b}
// applyOperation takes a function as a parameter.func applyOperation(x, y int, op func(int, int) int) int { return op(x, y)}
func main() { // Assign a function to a variable. var operation func(int, int) int = multiply fmt.Println(operation(4, 5))
// Pass a function as an argument. fmt.Println(applyOperation(6, 7, multiply))
// Pass an anonymous function inline. fmt.Println(applyOperation(2, 3, func(a, b int) int { return a + b }))}Click Run to see what this code prints.
Common Mistakes
- Forgetting a return statement in a function that has a declared, non-named return type — Go will refuse to compile.
- Confusing named return zero values with "no return needed" — you still need a return statement, even a bare one.
- Shadowing a named return variable by declaring a new local variable with := instead of assigning with =.
- Writing overly long functions with named returns, making it hard to track what value is actually returned where.
- Omitting types on grouped parameters incorrectly, e.g. writing func f(x, y string, z int) when x and z should share a type.
Best Practices
- Keep functions short and focused on one responsibility — this is idiomatic in Go and makes testing easier.
- Use named returns primarily for documentation value in short functions, not as a substitute for clear code.
- Group parameters of the same type to keep signatures concise and readable.
- Give functions clear, verb-based names that describe what they do (e.g., calculateTotal, not doStuff).
- Prefer explicit return statements over relying on named-return side effects when a function has multiple exit points.
Frequently Asked Questions
No, Go does not support default parameter values or function overloading. You typically use variadic parameters, optional struct fields, or multiple named functions instead.
No, they're entirely optional. Many idiomatic Go functions use plain, unnamed return types and explicit return statements.
Yes — these are anonymous functions (function literals), and they can also form closures, which you'll cover in an upcoming lesson.
Key Takeaways
- A function is declared with func name(parameters) returnType { ... }.
- Consecutive parameters sharing a type can omit the type on all but the last.
- Named return values pre-declare the return variables and support bare return statements.
- Functions are first-class values in Go — they can be stored in variables, passed around, and returned.
- Go does not support default parameters or overloading, unlike some other languages.
Summary
Functions are the building blocks of Go programs, and their explicit, typed signatures make code easy to read and reason about. Now that you understand basic declaration and return types, you're ready for one of Go's most distinctive features: returning multiple values from a single function.