我假设切片是通过引用传递的,但这似乎对值有效,但对数组本身无效。例如,如果我有这样的结构:
l := Line{
Points: []Point{
Point{3, 4},
},
}我可以定义一个变量,它会传递一个对结构切片的引用
slice := l.Points然后,如果我修改它,变量引用的原始结构将反映这些修改。
slice[0].X = 1000
fmt.Printf(
"This value %d is the same as this %d",
slice[0].X,
l.Points[0].X,
)这与数组的行为不同,我假设数组是通过值传递的。因此,例如,如果我使用数组定义了前面的代码:
l := Line{
Points: [1]Point{
Point{3, 4},
},
}
arr := l.Points
arr[0].X = 1000
fmt.Println(arr.[0].X != s.Points[0].X) // equals true, original struct is untouched那么,l结构就不会被修改。
现在,如果我想修改切片本身,我显然不能这样做:
slice = append(slice, Point{99, 100})因为这只会重新定义切片变量,从而丢失原始引用。我知道我可以简单地这样做:
l.Points = append(l.Points, Point{99, 100})但是,在某些情况下,使用另一个变量会更方便,而不必键入整个变量。
我试过这个:
*slice = append(*slice, Point{99, 100})但它不起作用,因为我试图取消引用显然不是指针的对象。
我最终尝试了一下:
slice := &l.Points
*slice = append(l.Points, Point{99, 100})它起作用了,但我不确定发生了什么。为什么slice的值没有被覆盖?append在这里是如何工作的?
发布于 2019-12-01 11:33:14
Append返回一个新的切片,它可能会修改初始切片的原始后备数组。原始切片仍将指向原始支持数组,而不是新的支持数组(它可能在内存中的相同位置,也可能不在内存中的相同位置)
例如(playground)
slice := []int{1,2,3}
fmt.Println(len(slice))
// Output: 3
newSlice := append(slice, 4)
fmt.Println(len(newSlice))
// Output: 4
fmt.Println(len(slice))
// Output: 3 虽然片可以被描述为“指向数组的胖指针”,但它不是指针,因此您不能取消对它的引用,这就是为什么会出现错误的原因。
通过创建一个指向切片的指针,并像上面那样使用append,您可以将指针所指向的切片设置为由append返回的“新”切片。
有关更多信息,请查看Go Slice Usage And Internals
发布于 2019-12-01 11:40:18
第一次尝试没有成功,因为切片不是指针,它们可以被认为是引用类型。Append将修改底层数组,如果它有足够的容量,否则它会返回一个新的切片。
你可以通过两次尝试的组合来实现你想要的。
l := Line{
Points: []Point{
Point{3, 4},
},
}
slice := &l.Points
for i := 0; i < 100; i++ {
*slice = append(*slice, Point{99 + i, 100 + i})
}
fmt.Println(l.Points)发布于 2019-12-04 02:58:09
我知道这可能是亵渎神明的,但对我来说,将切片看作结构是有用的。
type Slice struct {
len int
cap int
Array *[n]T // Pointer to array of type T
} 因为在像C这样的语言中,[]运算符也是一个解引用运算符,所以我们可以认为每次访问切片时,我们实际上是在解引用底层数组并为其赋值。这就是:
var s []int
s[0] = 1可能被认为等同于(在伪代码中):
var s Slice
*s.Array[0] = 1 这就是为什么我们可以说切片是“指针”。出于这个原因,它可以像这样修改它的底层数组:
myArray := [3]int{1,1,1}
mySlice := myArray[0:1]
mySlice = append(mySlice, 2, 3) // myArray == mySlice修改mySlice也会修改myArray,因为切片存储了指向数组的指针,并且在追加时,我们将取消对该指针的引用。
然而,这种行为并不总是这样的。如果超出了原始数组的容量,则会创建一个新数组,而原始数组保持不变。
myArray := [3]int{1,1,1}
mySlice := myArray[0:1]
mySlice = append(mySlice, 2, 3, 4, 5) // myArray != mySlice当我们试图将切片本身视为实际的指针时,就会产生混淆。因为我们可以通过附加到底层数组来修改它,所以我们相信在这种情况下:
sliceCopy := mySlice
sliceCopy = append(sliceCopy, 6)两个切片,slice和sliceCopy是相同的,但它们不是。我们必须显式地传递对片的内存地址的引用(使用&操作符)才能修改它。这就是:
sliceAddress := &mySlice
*sliceAddress = append(mySlice, 6) // or append(*sliceAddress, 6)另请参阅
https://stackoverflow.com/questions/59122177
复制相似问题