Working with GO, one is tempted to think that arrays and slices are the same things other than array having an immutable size. That's not true and some quirks should be known. Take the following function for example (for readability no checks are done on slice bounds):
type NamesStruct struct {
NamesArray [3]string
NamesSlice []string
}
func print(a NamesStruct) {
a.NamesArray[2] = "Massimiliano"
a.NamesSlice[2] = "Massimiliano"
fmt.Println("Printing Values inside called function:")
for i, _ := range a.NamesArray {
fmt.Printf("NamesArray[%d]=%s\n", i, a.NamesArray[i])
fmt.Printf("NamesSlice[%d]=%s\n", i, a.NamesSlice[i])
}
}
The print
function takes a struct containing an array (NamesArray
) and a slice (NamesSlice
) as parameters, changes the value of the second element of both and then prints their content.
Invoking it with a code like this:
a := NamesStruct{
NamesArray: [3]string{"Max", "Massimo", "Maximilian"},
NamesSlice: []string{"Max", "Massimo", "Maximilian"},
}
print(a)
fmt.Println("Printing Values inside caller function:")
for i, _ := range a.NamesArray {
fmt.Printf("NamesArray[%d]=%s\n", i, a.NamesArray[i])
fmt.Printf("NamesSlice[%d]=%s\n", i, a.NamesSlice[i])
}
we would expect the slice and the array to contain identical values both inside the caller function and in the called one. That's not the case. The output will be:
Printing Values inside called function:
NamesArray[0]=Max
NamesSlice[0]=Max
NamesArray[1]=Massimo
NamesSlice[1]=Massimo
NamesArray[2]=Massimiliano
NamesSlice[2]=Massimiliano
Printing Values inside caller function:
NamesArray[0]=Max
NamesSlice[0]=Max
NamesArray[1]=Massimo
NamesSlice[1]=Massimo
NamesArray[2]=Maximilian
NamesSlice[2]=Massimiliano
As you can see, the slice reflects the changes done inside the called function, but the array doesn't. Why? The reason is that Go passes EVERYTHING by value, but since the slice is basically a header pointing to a backing array, just that header is passed by value (thus pointing to the same backing array). The array, on the other hand, is copied and, thus, won't reflect the change.
package main
import "fmt"
type NamesStruct struct {
NamesArray [3]string
NamesSlice []string
}
func print(a NamesStruct) {
a.NamesArray[2] = "Massimiliano"
a.NamesSlice[2] = "Massimiliano"
fmt.Println("Printing Values from called function:")
for i, _ := range a.NamesArray {
fmt.Printf("NamesArray[%d]=%s\n", i, a.NamesArray[i])
fmt.Printf("NamesSlice[%d]=%s\n", i, a.NamesSlice[i])
}
}
func main() {
a := NamesStruct{
NamesArray: [3]string{"Max", "Massimo", "Maximilian"},
NamesSlice: []string{"Max", "Massimo", "Maximilian"},
}
print(a)
fmt.Println("Printing Values from caller function:")
for i, _ := range a.NamesArray {
fmt.Printf("NamesArray[%d]=%s\n", i, a.NamesArray[i])
fmt.Printf("NamesSlice[%d]=%s\n", i, a.NamesSlice[i])
}
}