Functions in Go
By Syncfusion®, Inc. · Last updated
Declare and call Go functions, pass parameters, return one, many or named values, and use variadic functions, closures, higher-order functions, recursion, defer and scope.
What Are Functions?
Function = a named group of steps that you can run again and again.
- You write the steps once.
- You call the function by its name whenever you need it.
- You can give it values, and it can give a value back.
You have already used functions:
main()is a function you wrote.fmt.Println()is a function from thefmtpackage.
Simple lesson: a function is a named recipe: write it once, use it many times.
A Real-World Example
Think of the school canteen's juice machine.
- You put in fruit: that is the input.
- The machine does the same steps every time: wash, cut, squeeze.
- Out comes juice: that is the output.
- You never need to know the steps. You just press the button.
Now the mapping:
- The machine = a function.
- The fruit = the parameters.
- The juice = the return value.
- Pressing the button = calling the function.
Functions make programs:
- shorter, because steps are not repeated
- easier to read, because each name explains a job
- easier to fix, because a mistake is fixed in one place
What You Will Learn
In this lesson, you will learn:
- How to declare and call a function.
- How to pass one or more parameters.
- How to return one, many, or named values.
- Variadic functions, anonymous functions and closures.
- How to pass functions to other functions.
- Recursion,
defer, and where variables can be seen (scope).
Function Fundamentals
Function Declaration
func name(parameters) returnType {
// steps
}
funcis the keyword that makes a function.- The name follows the naming rules from Variables and Constants.
- Functions are declared outside
main(), at the top level of the file.
Calling Functions
Call = run a function, by writing its name and ( ).
Declare once, call twice
package main
import "fmt"
func greet() {
fmt.Println("Good morning, Green Valley!")
}
func main() {
greet()
greet()
}
Good morning, Green Valley!
Good morning, Green Valley!
- Go starts at
main(). - Each
greet()jumps intogreet, runs its steps, then comes back.
Simple lesson: declare a function with func, then call it by name with ( ).
Parameters
Parameter = a variable in the function's brackets that receives a value.
Argument = the actual value you pass when you call it.
Single Parameters
One parameter
package main
import "fmt"
func welcome(name string) {
fmt.Println("Welcome,", name)
}
func main() {
welcome("Asha")
welcome("Ravi")
}
Welcome, Asha
Welcome, Ravi
name stringmeans: this function needs onestring."Asha"is the argument for the first call.
Multiple Parameters
Two parameters
package main
import "fmt"
func report(name string, marks int) {
fmt.Println(name, "scored", marks)
}
func area(length, width int) {
fmt.Println("Area:", length*width)
}
func main() {
report("Meena", 88)
area(12, 8)
}
Meena scored 88
Area: 96
- Separate parameters with commas.
length, width intis short forlength int, width int.- Arguments go in the same order as the parameters.
Go Passes Copies
Go gives a function a copy of each argument. Changing the copy does not change the original.
The original does not change
package main
import "fmt"
func addBonus(marks int) {
marks = marks + 10
fmt.Println("Inside:", marks)
}
func main() {
marks := 70
addBonus(marks)
fmt.Println("Outside:", marks)
}
Inside: 80
Outside: 70
- To change the original, return the new value, or use a pointer. See Pointers.
Go keeps functions simple:
- no default values for parameters
- no two functions with the same name (no overloading)
- every argument must be passed, in order
Simple lesson: parameters receive copies of the values you pass, in order.
Return Values
Return value = the value a function gives back with return.
Single Return Value
Return one value
package main
import "fmt"
func average(a, b, c int) float64 {
return float64(a+b+c) / 3
}
func main() {
avg := average(80, 90, 76)
fmt.Println(avg)
}
82
float64after the brackets is the return type.returnsends the value back and ends the function at once.
Multiple Return Values
Go functions can return more than one value.
Return two values
package main
import "fmt"
func divide(total, people int) (int, int) {
return total / people, total % people
}
func main() {
each, left := divide(17, 5)
fmt.Println("Each gets", each, "laddoos,", left, "left over")
}
Each gets 3 laddoos, 2 left over
- List the types in brackets:
(int, int). - Receive them with two names:
each, left := .... - Go uses this for errors:
value, err := strconv.Atoi("42").
Named Return Values
Named return values = return values that have names, like variables.
Named return values
package main
import "fmt"
func minMax(a, b, c int) (smallest, biggest int) {
smallest, biggest = a, a
for _, n := range []int{b, c} {
if n < smallest {
smallest = n
}
if n > biggest {
biggest = n
}
}
return
}
func main() {
low, high := minMax(72, 95, 64)
fmt.Println(low, high)
}
64 95
smallestandbiggeststart at their zero values.- A bare
returnsends back their current values. - Good for short functions. In long ones,
return smallest, biggestis clearer.
Simple lesson: return gives values back, and Go functions can return several at once.
Variadic Functions
Variadic function = a function that takes any number of arguments of one type.
Write ... before the type of the last parameter.
Add any number of marks
package main
import "fmt"
func total(marks ...int) int {
sum := 0
for _, m := range marks {
sum += m
}
return sum
}
func main() {
fmt.Println(total())
fmt.Println(total(90, 85))
fmt.Println(total(70, 80, 90, 100))
list := []int{10, 20, 30}
fmt.Println(total(list...))
}
0
175
340
60
- Inside the function,
marksis a slice:[]int. list...spreads a slice into separate arguments.fmt.Printlnitself is variadic. That is why it takes any number of values.
Simple lesson: ...type lets a function take as many values as you like.
Anonymous Functions and Closures
Function Literals
Anonymous function = a function with no name. It is also called a function literal.
Functions without names
package main
import "fmt"
func main() {
double := func(n int) int {
return n * 2
}
fmt.Println(double(21))
func(msg string) {
fmt.Println(msg)
}("Called right away")
}
42
Called right away
- You can store a function in a variable, like
double. - You can also call it at once by adding
( )after the}.
Closures and Lexical Scope
Closure = a function that remembers the variables around it, even after the outer function has finished.
Lexical scope = a function can see the variables of the code that surrounds it.
A token counter that remembers
tokenMakerhas finished, butnextis not lost.- The returned function closes over
next. That is why it is called a closure. - Each call to
tokenMaker()makes a new, separate counter.
Simple lesson: a function literal is a function without a name, and a closure is one that remembers its surroundings.
Higher-Order Functions
Higher-order function = a function that takes a function, or returns one.
Passing Functions
The type of a function is written like func(int) int.
Pass a rule into a function
package main
import "fmt"
func applyToAll(marks []int, rule func(int) int) {
for _, m := range marks {
fmt.Print(rule(m), " ")
}
fmt.Println()
}
func main() {
marks := []int{40, 65, 90}
addGrace := func(m int) int { return m + 5 }
outOfFifty := func(m int) int { return m / 2 }
applyToAll(marks, addGrace)
applyToAll(marks, outOfFifty)
}
45 70 95
20 32 45
applyToAlldoes not know the rule. It just calls it.- You choose the rule when you call it.
Returning Functions
A function that makes functions
package main
import "fmt"
func multiplier(k int) func(int) int {
return func(x int) int {
return x * k
}
}
func main() {
double := multiplier(2)
triple := multiplier(3)
fmt.Println(double(7), triple(7))
}
14 21
multiplier(2)builds a new function that remembersk = 2.- This is a closure too.
Simple lesson: functions are values: you can pass them in and return them.
Recursion
Recursion = a function that calls itself.
Base Case
Every recursive function needs two parts:
- Base case = the simple case that stops the calls.
- Recursive case = the function calls itself with a smaller problem.
Without a base case, the calls never stop.
Recursive Functions
Factorial of 4 = 4 × 3 × 2 × 1 = 24.
Press Play and watch the calls stack up, then come back down.
factorial(4), one call at a time
factorial with recursion
package main
import "fmt"
func factorial(n int) int {
if n <= 1 {
return 1
}
return n * factorial(n-1)
}
func main() {
fmt.Println(factorial(4))
fmt.Println(factorial(6))
}
24
720
- Call stack = the pile of function calls waiting for an answer.
- Each call waits on the stack until the call above it returns.
- Too many calls (no base case) fill the stack, and the program crashes.
Simple lesson: a recursive function calls itself on a smaller problem, and the base case stops it.
Deferred Calls
defer
defer = run this call later, just before the function ends.
- It is used for clean-up, like closing a file. See File Handling.
- The deferred call runs even if the function ends early.
defer runs at the end
package main
import "fmt"
func main() {
fmt.Println("Open the library")
defer fmt.Println("Lock the library")
fmt.Println("Issue books")
fmt.Println("Collect returns")
}
Open the library
Issue books
Collect returns
Lock the library
Multiple defer Statements
Many deferred calls run in reverse order: last in, first out.
Think of a stack of plates. The last plate you put on top is the first one you take off.
defer order
- The arguments of a deferred call are worked out when the
deferline runs, not at the end.
Simple lesson: defer saves a call for the end of the function, and many defers run in reverse order.
Function Scope
Scope = the part of the code where a name can be used.
Local Scope
Local variable = a variable made inside a function or block. It exists only there.
Package Scope
Package-level variable = a variable made outside every function. All functions in the package can use it.
Local and package scope
package main
import "fmt"
var school = "Green Valley School"
func printHeader() {
title := "Annual Report"
fmt.Println(school, "-", title)
}
func main() {
printHeader()
count := 3
if count > 0 {
message := "Students present"
fmt.Println(message, count)
}
fmt.Println(school)
}
Green Valley School - Annual Report
Students present 3
Green Valley School
schoolis package scope: both functions use it.titlelives only insideprintHeader.messagelives only inside theifblock.
Shadowing
Shadowing = an inner variable with the same name hides the outer one.
An inner variable hides the outer one
package main
import "fmt"
var level = "school"
func main() {
level := "class"
fmt.Println(level)
{
level := "bench"
fmt.Println(level)
}
fmt.Println(level)
}
class
bench
class
- Each
:=makes a new variable in a smaller scope. - Shadowing is legal, but it confuses readers. Use different names.
Easy way to remember
- Made inside
{ }= lives inside those{ }. - Made outside every function = the whole package can use it.
- Keep variables in the smallest scope that works.
Simple lesson: a variable lives only inside the braces where it was made.
TL;DR
- Function =
func name(params) returnType { }. Call it withname(args). - Parameters = inputs. Go passes copies.
Return values =
return x. Go can return many:(int, error).- Named returns =
(total int), then a barereturn.
- Named returns =
- Variadic =
func sum(nums ...int). Spread a slice withlist.... Anonymous function =
func(x int) int { ... }.- Closure = a function that remembers outer variables.
- Higher-order = takes or returns a function.
- Recursion = a function calls itself. Needs a base case.
- defer = run at the end, in reverse order.
- Scope = local (inside
{ }) or package (outside functions).
Common mistakes
| Mistake | Wrong idea | Correct idea | What goes wrong |
|---|---|---|---|
A function inside main() with func name() | Named functions can go anywhere | Named functions go at the top level | A syntax error. Use a function literal inside. |
Forgetting return in a function with a return type | Go returns the last value | Every path must return | missing return |
| Changing a parameter to change the caller's variable | Parameters are the same box | Parameters are copies | The original does not change. |
a, b := f() when f returns one value | You can take as many as you like | Take exactly as many as it returns | assignment mismatch |
| Recursion with no base case | It stops by itself | A base case must stop it | The stack overflows and the program crashes. |
Expecting defer to run in written order | First defer runs first | Last defer runs first | Clean-up happens in the wrong order. |
| Using a local variable in another function | Variables are shared | Locals live inside their braces | undefined: title |
Check Yourself
Exercises
What to Remember
- A function is a named recipe:
func name(params) returnType { }. - Parameters get copies. Go functions can return many values.
...typemakes a function take any number of values.- Functions are values: you can store them, pass them and return them.
- A closure remembers the variables around it.
- Recursion needs a base case.
deferruns at the end, in reverse order. - A variable lives inside the braces where it was made.
Next: Packages and Modules. You will learn how Go organises code into packages, and how modules manage a whole project.