Why does Go's slice has 'replication trap', but map does not?
Suppose we have a function that takes slice as an input parameter, and if slice is expanded in the function, only the copied slice structure is changed, instead of the original slice structure. The original slice still points to the original array, and the slice in the function has changed the array pointer because of the expansion.
func main() {
a := []int{1, 2}
fmt.Println(a) // [1 2]
doslice(a)
fmt.Println(a) // [1 2]
}
func doslice(a []int) {
a = append(a, 3, 4, 5, 6, 7, 8, 9)
a[0] = 200
fmt.Println(a) // [200 2 3 4 5 6 7 8 9]
}
Look at the output, if slice is passed by 'reference', it won't be like [1 2].
func main() {
mp := map[int]int{1:1,2:2}
domap(mp)
fmt.Println(mp) // map[1:1 2:2 3:3 4:4 ...], the same as below
}
func domap(mp map[int]int) {
for i := 3; i < 100; i++ {
mp[i] = i
}
fmt.Println(mp) // map[1:1 2:2 3:3 4:4 ...]
}
Look at this, the operation we've done in domap() worked! Is it a trap?! I mean, map is passed by 'reference'(*hmap) and slice is passed by 'value'(SliceHeader). Why is it that map and slice are designed to be all inner referenced types and why is it so inconsistent? Maybe it's just a design question, but why? Why slice and map like that?
Below is my guess about proving why map
can only be passed by 'reference':
Assume that map is passed by value -> hmap struct type
(1) After Init: (hmap outside the function)
hmap.buckets = bucketA
hmap.oldbuckets = nil
(2) After passing the param, entering the function: (hmap inside the function)
hmap.buckets = bucketA
hmap.oldbuckets = nil
(3) After triggering the expanding: (hmap inside the function)
hmap.buckets = bucketB
hmap.oldbuckets = bucketA
But slice
is different!
There is no incremental migration,
and there is no oldbuckets,
so you can use a structure because the function is isolated from the outside,
whereas map is not, and oldbuckets are referenced outside the function.
I mean, the original purpose of this design may be passing value, to prevent direct modification of the original variable in the function, but map cannot be passed by value. Once the value is passed to the map, the original map data will be lost during the expansion of the function.
I will appreciate that if some one can help me solve this problem. Thanks a lot!
(I feel sorry for my poor Chinglish, I hope I described this well...:( It really troubled me a lot...)
FYI : are-slices-passed-by-value