Relationship between slice and array
A slice isn't an array, it's a struct which consists of a pointer to array element, and length of segment, and arr capacity(length). So you can consider it uses pointer and length to slice an array. When you manipulate a slice, it will return new slice, but the array under the hood may not allocate. This may cause side effect.
You can find the source code of slice here:
type slice struct {
array unsafe.Pointer
len int
cap int
}
Let's write some code and draw a diagram to represent the concept.
s1:=[]int{1,2,3}
// cut slice : change len
s2:= s1[:2]
// cut slice : change len and pointer to array element
s3 := s1[1:3]
Potential issue -- manipulate the same array
Sometimes bug will happen when you manipulate slices both point to the same array. Like the following code, I just want to change the value in S2 only, but it affects s1 and s3, because they both point to the same array.
func main() {
s1 := []int{1, 2, 3}
s2 := s1[:2]
s3 := s1[1:3]
fmt.Printf("%v\n%v\n%v\n", s1, s2, s3)
fmt.Println("-----")
s2[1] = 0
fmt.Printf("%v\n%v\n%v\n", s1, s2, s3)
}
output:
[1 2 3]
[1 2]
[2 3]
----------
[1 0 3]
[1 0]
[0 3]
How to avoid?
just work on the last slice. If you don't need other slice, of course it has no risk, but if you can't, there's two function to copy new slice.
use built-in function "func copy(dst, src []Type) int",
copy function will only copy elements, based on len of dst, from src
func main() {
s1 := []int{1, 2, 3}
s2 := make([]int,2)
copy(s2, s1)
s3 := make([]int,2)
copy(s3, s1[1:])
fmt.Printf("%v\n%v\n%v\n", s1, s2, s3)
fmt.Println("-----")
s2[1] = 0
fmt.Printf("%v\n%v\n%v\n", s1, s2, s3)
}
output:
[1 2 3]
[1 2]
[2 3]
-----
[1 2 3]
[1 0]
[2 3]
- use built-in function "func append(slice []Type, elems ...Type) []Type", when you append to empty slice, it will allocate the array and make a copy.
func main() {
s1 := []int{1, 2, 3}
s2 := append([]int{}, s1...)
s3 := append([]int{}, s1[1:]...)
fmt.Printf("%v\n%v\n%v\n", s1, s2, s3)
fmt.Println("-----")
s2[1] = 0
fmt.Printf("%v\n%v\n%v\n", s1, s2, s3)
}
output:
[1 2 3]
[1 2]
[2 3]
-----
[1 2 3]
[1 0]
[2 3]
Personally, I prefer to use append, because it's shorter and less code, but append can also make another issue because of allocating. Let's discuss the allocating mechanism in next article.
Top comments (0)