Parameters are copies
What you'll learn:
- explain why a function changes only a copy of its parameter, and return a new value with
return; - return several results from a function and discard the ones you don't need with
_; - write recursive functions with a base case;
- tell where a variable is visible and what shadowing is.

A function is handy to picture as a machine with a photocopier inside. You lay a sheet with a number on the glass, the machine does something with that number and hands out a finished sheet:
- what you lay on the glass are the function's parameters;
- the sheet that comes out is the result it returns with
return.
This machine has one peculiarity: it never touches your sheet. Before it starts, it takes a copy and works on the copy, while the original stays on the glass.
Let's see how this looks in code. The function double doubles n, while the variable x in main stays the same:
package main
import "fmt"
func double(n int) {
n = n * 2
fmt.Println("inside:", n) // inside: 10
}
func main() {
x := 5
double(x)
fmt.Println("outside:", x) // outside: 5
}Pass by value
Let's walk through the example line by line:
x := 5creates the variablexinmain.- When
double(x)is called, the value of the argumentxis copied into the parametern. n = n * 2turns the copy into10.- The first
Printlnprintsinside: 10. - The function returns, and the second
Printlnprintsoutside: 5.
This walkthrough used two words that people often mix up:
- a parameter is a name in the function's declaration:
ninfunc double(n int); - an argument is the value passed at the call:
xindouble(x).
This way of passing is called pass by value. The function gets a copy of the argument, not the variable itself.
The machine takes a copy on every run, and Go copies the argument on every call. For a number this is a fast operation, and you never notice it.
Interviewers like to ask this: "Does Go pass arguments by value or by reference?" The answer has two parts:
- always by value, and this holds for every argument, not only numbers;
- assigning to a parameter never changes the caller's variable.
A parameter is a separate variable
A parameter is an ordinary variable of the function:
- you can read it, change it with
=and++, and pass it to other calls; - it is created on every call and disappears when the function returns;
- it has no connection to the caller's variable.
There are two cases where a connection seems to exist, though there is none.
An expression as the argument
An argument can be an expression, not only a variable. In the call double(x + 1) the sum 6 is computed first, and its value goes into n. The function sees only the number and does not know how it was produced.
Matching names
Matching names connect nothing either. If you name the parameter x, like the variable in main, there are still two variables. Each is visible only in its own function, and changing one does not touch the other.
Return a new value
A function connects to the calling code in only two ways:
- arguments going in;
- a result coming out.
For the caller to get the changed value, the function returns it with return. The caller decides what to do with the result: print it, store it in a new variable, or write it back into x.
package main
import "fmt"
func doubled(x int) int {
x = x * 2
return x
}
func main() {
x := 5
fmt.Println(x, doubled(x)) // 5 10
x = doubled(x)
fmt.Println(x) // 10
}Let's walk through main line by line:
x := 5creates the variablexinmain.fmt.Println(x, doubled(x))callsdoubled: the function changes its parameterxand returns10, whilexinmainstays5. The line prints5 10.x = doubled(x)writes the result of the second call back intox.fmt.Println(x)prints10: the variable changed only after the assignment.
The machine handed out a new sheet, and you put it in place of the old one yourself.
Common mistake
The function returns a new value, but the result of the call is not stored anywhere:
x := 5
doubled(x) // ✗
fmt.Println(x)The program compiles and prints 5. A function call can be written as a statement on its own even when it returns something, and then the result is lost. The dish is ready, but nobody took it. The compiler does not warn about this, so assign the result explicitly: x = doubled(x).
Key points
- A parameter is a copy of the argument: changes inside the function are not visible outside.
- Go always passes arguments by value.
- For the caller to get a new value, the function returns it and the caller assigns it:
x = doubled(x).
Subscribe to take the course
The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.