Functions
By the end of this lesson you'll write Go functions that take typed parameters, return one or many values, accept any number of arguments, capture state as closures, and schedule cleanup with defer — the everyday building blocks of every Go program.
Learn Python, JavaScript, Java and more with free interactive lessons, real projects and AI-powered help. Beginner-friendly.
Part of the free Go course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
What You'll Learn in This Lesson
1️⃣ Function Basics: Parameters and Return Type
A function packages code you can reuse by name. The header is func name(parameter type) returnType — you state the type of each parameter and the type it gives back. When neighbouring parameters share a type you write it once ( a, b int ). A function with no return type simply does work and hands nothing back. Read this worked example and run it first.
Your turn. The function header below is missing its parameter type, its return type, and the value it returns. Fill in the three ___ blanks using the hints, then run it.
2️⃣ Multiple and Named Return Values
Go functions can return more than one value , and this is the foundation of how Go reports errors: a function returns its result plus an error , and you check the error before trusting the result. You can also name the return values in the header; then a bare return (a "naked return") hands back those named variables. One rule the compiler enforces: you must use every returned value, or explicitly discard it with the blank identifier _ .
Now you try. minMax already returns two values — your job is to capture them. Fill in the blanks, using _ where a value isn't needed.
3️⃣ Variadic Functions: Any Number of Arguments
Sometimes you don't know how many arguments you'll get — think "sum all of these". A variadic parameter, written nums ...int , accepts zero or more values, and inside the function nums is just a slice ( []int ) you can range over. If you already have a slice, "spread" it into the call with slice... .
4️⃣ Functions as Values and Closures
In Go a function is a first-class value : you can store it in a variable, pass it to another function, and return it from one. A function returned this way can "remember" variables from where it was created — that's a closure . Each closure gets its own private copy of those variables, which survives between calls. This is how you build counters, generators, and configurable behaviour without globals.
5️⃣ defer: Cleanup That Always Runs
defer schedules a function call to run when the surrounding function exits — perfect for cleanup like file.Close() right next to where you opened it, so you can never forget it. Two rules to burn in: deferred calls run in LIFO order (last deferred, first to run), and a defer's arguments are evaluated immediately , even though the call happens later. Watch both in the output below.
📋 Quick Reference
No blanks this time — just a brief and an outline. Write the whole stats function yourself, combining a variadic parameter with multiple return values. Run it and check your output against the expected line.
Practice quiz
What is the shape of a Go function header?
- func returnType name(params)
- def name(params) -> type
- func name(parameter type) returnType
- function name(params): type
Answer: func name(parameter type) returnType. Go writes func name(parameter type) returnType, with parameter types after the names.
For func add(a, b int) int, what does the shared type mean?
- both a and b are int
- a is int, b is untyped
- a and b are different types
- it is a syntax error
Answer: both a and b are int. When neighbouring parameters share a type you list it once; a and b are both int.
By Go convention, the error is which return value?
- the first
- the only
- it is never returned
- the last
Answer: the last. Fallible functions return (result, error) with error as the final value.
What does a bare return require?
- no special setup
- named return values in the header
- a single return value
- a deferred call
Answer: named return values in the header. A naked (bare) return hands back the named return variables declared in the header.
What does fmt.Println(sum()) print for a variadic func sum(nums ...int) int?
- 0
- nil
- an error
- nothing compiles
Answer: 0. Calling a variadic with no arguments is allowed; the empty sum is 0.
How do you spread a slice scores into a variadic call?
- sum(scores)
- sum(...scores)
- sum(scores...)
- sum(&scores)
Answer: sum(scores...). Append ... after the slice: sum(scores...) passes its elements as the variadic args.
What must you do with every value a function returns?
- log it
- use it or discard it with _
- store it in a global
- ignore it freely
Answer: use it or discard it with _. Go won't compile if you capture a value you never read; discard with the blank identifier _.
When are a deferred call's arguments evaluated?
- when the function exits
- never
- at the next defer
- immediately at the defer statement
Answer: immediately at the defer statement. Arguments are evaluated at the defer line; the call itself runs at function exit.
In what order do multiple deferred calls run?
- FIFO (first deferred, first run)
- LIFO (last deferred, first run)
- alphabetical
- random
Answer: LIFO (last deferred, first run). Defers run in LIFO order — the last deferred call runs first.
A function stored in a variable that remembers surrounding variables is called...
- a method
- a goroutine
- a closure
- an interface
Answer: a closure. A closure captures variables from where it was created and keeps its own state.