This is an old revision of the document!
The problem is compounded by the fact that there is no syntactic cue to distinguish values and references in Go. Pointer variable declarations are explicit thanks to the
* symbol. In Java, reference types are always written with an initial upper case, like
In Go there are no visual clues: you have to know and remember that variables of built-in types like
chan and slices behave as references.
Yes. But what are the values?
If you have an array with 1 million elements and you pass that array to a function directly (without using a pointer), the entire array with 1 million elements will be copied to the parameter variable, which is a local variable in the function.
However, if you pass a slice to a function, the elements are not copied. The value of a slice is a hidden struct describing the it. It has three fields:
intholding the current length of the slice;
intholding the capacity – the maximum number of elements the slice can contain.
So the only data copied when you pass a slice to a function is that 3-field struct. This has two very important consequences:
Other types like
string are also represented by implicit structs containing pointers. The
string type is immutable, so the fact that its handled like a reference variable is a harmless optimization. But maps and channels are mutable, so the caveats I mentioned for slices also apply: always keep in mind that passing one of those to a function means the function will be able to modify the referenced value, whether you want it or not.
In the case of a channel, we naturally expect it will be consumed or fed by the function. For maps and slices, that is not the case, and subtle bugs may happen if a function is unexpectedly changing the data we pass to it.
It is interesting to note that slices, maps and channels are built using the
make function, which is one of the few generic functions in Go: it takes types as arguments.1)
unsafeinspection of slice values.