在golang中,片和map都是引用类型。当您只需要修改切片/映射中的元素时,对片/映射成员的修改将被“广播”到所有切片。考虑到m1 := make(map[int]int); m2 := m1,m1[3] = 5会导致m2[3] == 5。
但是,当您尝试向这两种类型中添加新元素时,情况就开始不同了。如下面的示例所示,添加到map param中的新元素将在参数中自动显示;但是,添加到片中的新元素将在参数中被“丢弃”。
问题是,为什么这是不同的?
func editMap(m map[int]int) {
m[3] = 8
m[4] = 9
}
func editSlice(s []int) {
s = append(s, 5)
s = append(s, 9)
}
func main() {
m := make(map[int]int, 0)
m[1] = 5
m[2] = 3
fmt.Printf("%v\n", m) //map[1:5 2:3]
editMap(m)
fmt.Printf("%v\n", m) //map[1:5 2:3 3:8 4:9]
s := make([]int, 2)
s[0] = 2
s[1] = 5
fmt.Printf("%v\n", s) //[2 5]
editSlice(s)
fmt.Printf("%v\n", s) //[2 5]
}编辑:我可能不清楚这个问题的意图,请让我重新表述它(对不起,并感谢所有的内部细节)。
我真正想问的是,显然map是作为一个指针来实现的,用于隐藏散列映射的所有细节;为什么没有类似的实现呢?
但是,从API的角度(我们这样的golang用户之间的API和Ross Cox这样的golang维护者之间的API)来看,当前的切片实现确实是非常轻量级的,这两种“引用”类型的API并不统一,可能会给新来的开发人员带来陷阱。
发布于 2017-12-01 09:41:38
行为的区别在于这些类型的实现。
映射是指向数据结构的指针,而切片是包含指向支持数组的指针、切片长度和容量的小结构。reflect.SliceHeader对片头进行了建模:
type SliceHeader struct {
Data uintptr
Len int
Cap int
}这是偏差的主要原因:指针与结构。
将新元素添加到映射时,指针将保持不变。指向的映射结构可能会更改,但映射指针不会更改。
更改片的元素时,可以有效地更改支持数组的元素。切片头不会更改:它将继续持有相同的指针、长度和容量。任何切片值(切片头)的副本都指向相同的支持数组,因此,所有人都将看到已更改的元素。
当您向片中添加新元素时,描述新片(其中包含附加元素)的片头必须更改:长度必须增加1,指针和容量也可能发生变化(如果必须分配新的支持数组以容纳新元素)。
每件事都是以价值来传递的。这是第二个偏差的原因。当一个切片被传递时,一个副本是从头创建的,如果某个东西被附加到副本中,即使结果被正确地分配回它(返回到副本),原始的片头将不知道这一点。
在传递映射时,映射值(即指针)也将被复制,但原始映射指针和复制映射指针都将指向相同的映射结构。通过任何这些指针添加值或更改映射,都将更改唯一且仅指向的映射结构。
要使它们的行为相同,您必须使它们具有相同的类型,即:指针。如上所述,地图已经是(隐藏的)指针。如果您继续并开始将指针传递给片,并且对指向的值进行操作,它们的行为将与映射相同。在实践中,这很少被使用(帮助使用片指针的语言支持甚至少于数组指针),相反,替代方法是在返回新切片的地方广泛使用。你可以在这里读到更多关于它的信息:切片作为参数传递的切片指针
发布于 2017-12-01 10:39:36
要修改切片,只需编辑如下代码(https://play.golang.org/p/2SeP93itIL):
func editSlice(s *[]int) {
*s = append(*s, 5)
*s = append(*s, 9)
}在有效围棋中有一些解释
如果一个函数使用了一个切片参数,那么它将使变为切片的 elements,调用者就会看到它。
这就是为什么这个切片的修改参数对调用者是可见的,但是在您返回它或分配给现有变量之前,新的切片本身是不可见的。因为append返回一个新的切片
之后我们必须返回切片,因为尽管追加可以修改片的元素,但本身是(保存指针、长度和容量的运行时数据结构)是通过值传递的。
发布于 2017-12-02 16:05:54
如果两个对象具有相同的内存地址,那么如果您更改其中一个的值,另一个就会更改,因为它们实际上是一个对象。
在您的代码中,m在editMap中,m在main中具有相同的值:是同一个字典对象的地址。然而,s在editSlice中的值和s在main中的值是两个不同的对象。
我希望我的解释足够清楚。
https://stackoverflow.com/questions/47590444
复制相似问题