The value of the data generated in the "range" statement is actually a copy of the collection element. They are not references to the original elements.
This means that updating these values will not modify the original data.
Let's look at the example directly:
package main import "fmt" func main() { data := []int{1, 2, 3} for _, v := range data { v *= 10 //The original element has not changed } ("data:", data) //Output data: [1 2 3]}
If we need to update the data in the original collection, use the index operator to obtain the data:
package main import "fmt" func main() { data := []int{1, 2, 3} for i, _ := range data { data[i] *= 10 } ("data:", data) //Output data: [10 20 30]}
OK, the key point is here! The key point is here! The key point is here! Say it three times, most bloggers may get stuck.
Here I will summarize in advance:
Multiple slices can refer to the same data. For example, this happens when you create a new slice from an existing slice (such as intercepting via index).
If your application functions require this behavior, you will need to pay attention to the "pit" of slice.
In some cases, adding new data in a slice will result in a new array being allocated when the original array cannot hold more new data.
The other slices also point to old arrays (or old data).
package main import "fmt" func main() { s1 := []int{1, 2, 3} (len(s1), cap(s1), s1) //Output 3 3 [1 2 3] s2 := s1[1:] //The index starts with the second element intercept (len(s2), cap(s2), s2) //Output 2 2 [2 3] for i := range s2 { s2[i] += 20 } // Still refer to the same array (s1) //s1 modified the last two elements in s2, so s1 has also been updated. Output [1 22 23] (s2) //Output [22 23] s2 = append(s2, 4) // Note that the capacity of s2 is 2. Appending a new element will cause a new array to be allocated [22 23 4] for i := range s2 { s2[i] += 10 } //s1 is still the updated historical old data (s1) //Output [1 22 23] (s2) //Output [32 33 14]}
Therefore, everyone pays special attention when using it. Insufficient capacity, adding new elements will not affect historical data. Because variables have been reassigned.
In addition, let’s continue to talk about some advanced skills:
Use pointer to receive the value of the method
As long as the value is addressable, it is no problem to call the pointer receiving method on this value.
However, not all variables are addressable. The element of the Map is not. Nor is the variable referenced through the interface. Let's continue to look at the following code:
package main import "fmt" type user struct { name string } func (p *user) print() { ("Ranking:", ) } type printer interface { print() } func main() { u := user{"Qiao Feng"} () // Output Ranking: Qiao Feng var in printer = user{"Jiumozhi"} //error () m := map[string]user{"one": user{"The wind is clear and bright"}} m["one"].print() //error }
Output:
cannot use user literal (type user) as type printer in assignment: user does not implement printer (print method has pointer receiver) cannot call pointer method on m["one"] cannot take the address of m["one"]
It roughly means: data text (type data) cannot be used as type pointer in assignment, user does not execute pointer call (pointer method has pointer receiver),
The pointer method cannot be called on m["one"], and the address of m cannot be taken ["one"].
Above we see that there is a map with a struct value, and we cannot update a single struct value. For example, the wrong code:
package main type user struct { name string } func main() { m := map[string]user{"one": {"Qiao Feng"}} m["one"].name = "The wind is clear and bright" //Output cannot assign to struct field m["one"].name in map}
The error means: In map, it cannot be assigned to the structure field m["one"].name. This operation is invalid because the map element cannot be accessed.
We mentioned above: the slice element can be used to retrieve the address:
package main import "fmt" type user struct { name string } func main() { one := user{"Qiao Feng"} u := []user{one} u[0].name = "The wind is clear and bright" //ok (u) //Output: [{Feng Qingyang}]}
Of course we have a better solution:
The first effective method is to use a temporary variable:
package main import "fmt" type user struct { name string } func main() { m := map[string]user{"one": {"Qiao Feng"}} u := m["one"] //Use temporary variables = "The wind is clear and bright" m["one"] = u ("%v\n", m) //Output: map[one:{Feng Qingyang}]}
Another effective way is to use a pointer map:
package main import "fmt" type user struct { name string } func main() { m := map[string]*user{"one": {"Qiao Feng"}} m["one"].name = "The wind is clear and bright" //ok (m["one"]) //Output: &{Feng Qingyang}}
Speaking of this, let me mention it again by the way. Continue to read the following code:
package main import "fmt" type user struct { name string } func main() { m := map[string]*user{"one": {"Qiao Feng"}} m["two"].name = "Jiumozhi" //Add a custom key name value (m["two"]) //error }
Output:
panic: runtime error: invalid memory address or nil pointer dereference
Invalid memory address or dereference null pointer? The reason is that Go cannot dynamically add fields to the structure, we can indirectly use make(map[string]interface{}) to implement it.
Well, that’s all I have said. If there are any shortcomings, please leave a message to correct me. . . . . . .
Supplement: Comparison of index speeds of map and slice in golang
Main file
package main var max = 100 var Slice = make([]int, max+10) var Map = make(map[int]int) func init() { for i := 0; i < max; i++ { Slice[i] = i Map[i] = i } } // The search algorithm can be optimized. This article compares common unordered searches.func SearchSlice(i int) int { for _, v := range Slice { if v == i { return v } } return -1 } func SearchMap(i int) int { return Map[i] }
Test files
package main import "testing" func BenchmarkSearchMap(b *) { for i := 0; i < ; i++ { _ = SearchMap(i % max) } } func BenchmarkSearchSlice(b *) { for i := 0; i < ; i++ { _ = SearchSlice(i % max) } } func BenchmarkSlice(b *) { for i := 0; i < ; i++ { _ = Slice[i%max] } }
Test results
max = 100
BenchmarkSearchMap-16 94148293 12.7 ns/op 0 B/op 0 allocs/op BenchmarkSearchSlice-16 49473447 23.6 ns/op 0 B/op 0 allocs/op BenchmarkSlice-16 187461336 6.46 ns/op 0 B/op 0 allocs/op
max = 10000
BenchmarkSearchMap-16 43147364 27.6 ns/op 0 B/op 0 allocs/op BenchmarkSearchSlice-16 968623 1159 ns/op 0 B/op 0 allocs/op BenchmarkSlice-16 187649472 6.42 ns/op 0 B/op 0 allocs/op
Max = 1000000
BenchmarkSearchMap-16 15015690 90.1 ns/op 0 B/op 0 allocs/op BenchmarkSearchSlice-16 441436 104242 ns/op 0 B/op 0 allocs/op BenchmarkSlice-16 182620702 6.58 ns/op 0 B/op 0 allocs/op
Under some specific optimization conditions, you can try to use slice, which will be better than map, such as optimizing the search for level 106 to 3 102. For some structures, you can classify according to certain features or sort them according to the feature values in advance.
The above is personal experience. I hope you can give you a reference and I hope you can support me more. If there are any mistakes or no complete considerations, I would like to give you advice.