Strictly speaking, there is only one way to pass parameters in Go - by value. Every time a variable is passed as parameter, a new copy of the variable is created and passed to called function or method. The copy is allocated at a different memory address.
In case a variable is passed by pointer, a new copy of pointer to the same memory address is created. To feel the difference, let’s have a look at how it all works on example.
A choice is sometimes predetermined by usage context. Let’s have a look at the most common use cases.
Variable must not be modified
We do not have other option, but pass variable by value. So that variable cannot be modified downstream. And vice versa, if variable is expected to be modified, it must be passed by pointer.
Variable is a large struct
If variable is a large struct and performance is an issue, it’s preferable to pass variable by pointer. So that to avoid expensive copying of the whole struct in memory.
Variable is a map or slice
Maps and slices are reference types in Go and should be passed by values.
Even though Go looks a bit like C, its compiler works differently. And C analogy does not always work with Go. Passing by value in Go may be significantly cheaper than passing by pointer.
This happens because Go uses escape analysis to determine if variable can be safely allocated on function’s stack frame, which could be much cheaper then allocating variable on the heap. Passing by value simplifies escape analysis in Go and gives variable a better chance to be allocated on the stack.