Pointers 为什么我不能将值附加到结构';使用引用进行切片?
我假设切片是通过引用传递的,但这似乎适用于值 但不适用于阵列本身。例如,如果我有这个结构:Pointers 为什么我不能将值附加到结构';使用引用进行切片?,pointers,go,slice,Pointers,Go,Slice,我假设切片是通过引用传递的,但这似乎适用于值 但不适用于阵列本身。例如,如果我有这个结构: l := Line{ Points: []Point{ Point{3, 4}, }, } 我可以定义一个变量,该变量被传递到结构的切片的引用 slice := l.Points 如果我修改它,变量引用的原始结构 将反映这些修改 slice[0].X = 1000 fmt.Printf( "This value %d is
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})
因为这只会重新定义slice变量,从而丢失原始引用。
我知道我可以做到这一点:
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(*slice, Point{99, 100})
slice := &l.Points
*slice = append(l.Points, Point{99, 100})
这是可行的,但我不确定发生了什么。为什么切片的值没有被覆盖?
append
在这里是如何工作的?append返回一个新切片,该切片可能会修改初始切片的原始备份数组。原始片仍将指向原始备份阵列,而不是新的备份阵列(可能在内存中的同一位置,也可能不在内存中的同一位置)
例如()
虽然切片可以描述为“指向数组的胖指针”,但它不是指针,因此不能取消对它的引用,这就是为什么会出现错误
通过创建指向切片的指针,并像上面那样使用append
,可以将指针指向的切片设置为append
返回的“新”切片
有关详细信息,请查看您的第一次尝试失败,因为切片不是指针,它们可以被视为引用类型。如果Append有足够的容量,它将修改底层数组,否则它将返回一个新的切片 你可以通过两次尝试的结合来实现你想要的
l:=行{
点数:[]点数{
第{3,4}点,
},
}
切片:=&l.点
对于i:=0;i<100;i++{
*切片=追加(*切片,点{99+i,100+i})
}
fmt.Println(l.点)
我们先不提术语问题。该词的使用方式与您使用该词的方式不同。然而Go确实有指针,指针是一种引用形式。此外,切片和映射有点特殊,因为对于某些类型的T或类型对T1和T2.1,切片下的数组或映射的存储可能已经存在,也可能不存在,或者通过声明或定义一个类型为slice of T
或map[T1]T2
的变量来创建
我们可以将您在谈论时使用的单词reference表示显式指针,例如:
func f1(p *int) {
// code ...
}
以及在谈论以下内容时隐含的指针:
func f2(m map[T1]T2) { ... }
func f3(s []T) { ... }
在f1
中,p
实际上是一个指针:因此它指的是一些实际的int
,或者是nil
。在f2
中,m
指的是一些底层映射,或者是nil
。在f3
中,s
指的是一些底层数组,或者是nil
但如果你写:
那么你一定写过:
type Line struct {
// ... maybe some fields here ...
Points []Point
// ... maybe more fields here ...
}
此行
是一种结构类型。它不是切片类型;它不是地图类型。它包含一个切片类型,但它本身不是切片类型
你现在谈论的是传递这些切片。如果传递l
,则按值传递整个struct
。区分这一点和传递l.Points
的值非常重要。接收其中一个参数的函数必须使用正确的类型声明它
因此,在大多数情况下,谈论参考文献只是一种转移注意力的手段——从实际发生的事情中转移注意力。我们需要知道的是:您分配了哪些变量值,使用了哪些源代码
抛开这些,让我们谈谈您的实际代码示例:
这正是它所说的:
- 将
传递到l.Points
,这是一个内置的,因为它在某种程度上具有神奇的类型灵活性(与Go的其他部分相比,Go的类型非常严格)。它接受类型为append
的任何值(T的一部分,用于任何有效类型T)加上类型为[]T
的一个或多个值,并生成相同类型的新值T
[]T
- 将结果分配给
l.Points
append
执行其工作时,它可能:
- receive
(给定类型):在本例中,它创建基础数组,或nil
- 接收一个非nil片:在这种情况下,它会写入底层数组或丢弃该数组,以便根据需要使用新的更大容量数组。2
l.Points
将更新引用基础数组的唯一切片变量
然而,我们可以打破这些假设:
s2 := l.Points
现在l.点
和s2
都指向(单个)底层数组。修改基础数组的操作将至少潜在地影响s2
和l.Points
您的第二个示例本身就可以:
但是您还没有展示如何声明和/或分配切片本身
您的第三个示例也很好:
其中第一行声明并初始化slice
以指向l.Points
。因此,变量slice
具有类型*[]点<
l.Points = append(l.Points, Point{99, 100})
s2 := l.Points
*slice = append(*slice, Point{99, 100})
slice := &l.Points
*slice = append(l.Points, Point{99, 100})
*slice = append(*slice, Point{99, 100})
l.Points = append(*slice, Point{99, 100})
var s []int
var s = []int{42}
type Slice struct {
len int
cap int
Array *[n]T // Pointer to array of type T
}
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
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)
sliceAddress := &mySlice
*sliceAddress = append(mySlice, 6) // or append(*sliceAddress, 6)