Functions are declared with the func keyword. Parameter names come before their types, and the return type comes after the parameter list.
Keep Golang functions focused. A function should usually do one clear thing: parse input, validate a value, calculate a result, call a dependency, or write a response. Smaller functions are easier to test and easier to reuse.
| Part | Example | Meaning |
|---|---|---|
| Keyword | func | Starts a function declaration |
| Parameters | a int, b int | Inputs accepted by the function |
| Return type | int | Value returned by the function |
package main
import "fmt"
func add(a int, b int) int {
return a + b
}
func main() {
fmt.Println(add(10, 20))
}
When consecutive parameters share the same type, you can write the type once after the last name. This is common in small helpers and mathematical functions.
Do not over-compress signatures if readability suffers. A longer but clearer signature is better than a clever one, especially when parameters represent different concepts.
func multiply(width, height int) int {
return width * height
}
func formatName(first, last string) string {
return first + " " + last
}
func createUser(name string, age int, active bool) User {
return User{Name: name, Age: age, Active: active}
}
Multiple return values are a major Golang feature. The most common pattern returns a useful value plus an error. This makes failure visible in the signature and forces callers to decide what to do.
Return the zero value for the successful result when returning an error. For example, return 0, err for a number, "", err for a string, or nil, err for a pointer, slice, map, or interface.
package main
import (
"errors"
"fmt"
)
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}
func main() {
result, err := divide(20, 4)
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println(result)
}
Golang allows named return values. They can improve documentation for short functions, but they can also make longer functions harder to follow if values are changed far from the return statement.
Use named returns carefully. In most application code, explicit return values are easier for beginners and reviewers to understand because the returned values are visible at the return line.
| Return Style | Best Use |
|---|---|
| Explicit return values | Most normal functions |
| Named return values | Short functions where names clarify meaning |
| Naked return | Avoid in long functions because it hides what returns |
func splitName(fullName string) (first string, last string) {
parts := strings.Fields(fullName)
if len(parts) == 0 {
return "", ""
}
if len(parts) == 1 {
return parts[0], ""
}
return parts[0], parts[len(parts)-1]
}
A variadic parameter accepts zero or more values and behaves like a slice inside the function. Variadic functions are useful for logging fields, totals, middleware, optional labels, or functions where callers naturally pass a flexible number of values.
Only the final parameter can be variadic. If you already have a slice, pass it with ... to expand it into variadic arguments.
package main
import "fmt"
func sum(values ...int) int {
total := 0
for _, value := range values {
total += value
}
return total
}
func main() {
numbers := []int{10, 20, 30}
fmt.Println(sum(1, 2, 3))
fmt.Println(sum(numbers...))
}
Functions are values in Golang. You can assign them to variables, pass them to another function, or return them from a function. This is useful for callbacks, middleware, sorting, filtering, and test hooks.
A closure remembers variables from the scope where it was created. Use closures carefully when they mutate captured variables, especially with goroutines.
func makeCounter() func() int {
count := 0
return func() int {
count++
return count
}
}
counter := makeCounter()
fmt.Println(counter()) // 1
fmt.Println(counter()) // 2
defer schedules a function call to run when the surrounding function returns. It is commonly used to close files, unlock mutexes, finish spans, recover from panics at boundaries, or clean up temporary resources.
Deferred calls run in last-in, first-out order. Keep deferred work small and predictable so cleanup is easy to understand.
func readConfig(path string) ([]byte, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
return io.ReadAll(file)
}
func keyword.
defer is useful for predictable cleanup.
Explore 500+ free tutorials across 20+ languages and frameworks.