在Go中,我试图为我的旅行推销员问题做一个混乱的切片函数。在这样做的时候,我注意到当我开始编辑切片时,我给出的扰码函数在每次传入时都是不同的。
经过一些调试,我发现这是因为我编辑了函数中的切片。但既然围棋被认为是一种“通过价值传递”的语言,这怎么可能呢?
https://play.golang.org/p/mMivoH0TuV
我提供了一个操场链接来展示我的意思。通过删除第27行,您将得到一个与保留它不同的输出,这不会产生什么影响,因为函数应该在作为参数传入时创建自己的切片副本。
有人能解释一下这个现象吗?
发布于 2016-10-12 08:21:39
Go中的所有东西都是通过值传递的,切片也是如此。但是,切片值是一个头部,它描述支持数组的一个连续部分,而一个切片值只包含一个指向实际存储元素的数组的指针。切片值不包括其元素(与数组不同)。
因此,当您将一个切片传递给一个函数时,将从这个标头(包括指针)复制一个副本,该指针将指向相同的支持数组。修改切片的元素意味着修改支持数组的元素,因此所有共享相同支持数组的切片都将“观察”更改。
要查看片头中的内容,请查看reflect.SliceHeader类型:
type SliceHeader struct {
Data uintptr
Len int
Cap int
}见相关/可能重复的问题:函数切片参数与全局变量的性能?
阅读博客文章:Go切片:使用和内部
请注意,当您将切片传递给函数时,如果函数修改了片的“现有”元素,调用方将看到/观察更改。如果函数向切片添加新元素,则需要更改片头(长度最小,但也可能涉及分配一个新的支持数组),调用方将不会看到(除非返回新的片头)。
不使用映射,因为映射是遮挡下的指针,如果将映射传递给函数,并且函数向映射添加了一个新条目,则映射指针不会更改,因此调用方将在更改后不返回映射就可以看到已更改的映射(新条目)。
关于切片和映射,请参见Go中的地图初始化和为什么切片值有时会过时,但从不映射值?
发布于 2020-12-08 08:44:29
你可以在下面找到一个例子。简单地说,切片也是通过值传递的,但是原始的切片和复制的切片被链接到相同的基础数组。如果其中一个切片发生了更改,那么基础数组就会发生变化,那么另一个切片就会发生更改。
package main
import "fmt"
func main() {
x := []int{1, 10, 100, 1000}
double(x)
fmt.Println(x) // ----> 3 will print [2, 20, 200, 2000] (original slice changed)
}
func double(y []int) {
fmt.Println(y) // ----> 1 will print [1, 10, 100, 1000]
for i := 0; i < len(y); i++ {
y[i] *= 2
}
fmt.Println(y) // ----> 2 will print [2, 20, 200, 2000] (copy slice + under array changed)
}发布于 2020-06-06 11:50:14
当它传递的时候,它是通过指向基础数组的指针传递的,所以切片是一个指向底层数组的小结构。小结构被复制,但仍然指向相同的基础数组。包含片元素的内存块通过“引用”传递。存储容量、元素数和指向元素的指针的片信息三重态通过值传递。
处理传递到函数的切片的最佳方法(如果将切片的元素操作到函数中,并且我们不希望在元素内存块中反映这一点)是使用copy(s, *c)将它们复制为:
package main
import "fmt"
type Team []Person
type Person struct {
Name string
Age int
}
func main() {
team := Team{
Person{"Hasan", 34}, Person{"Karam", 32},
}
fmt.Printf("original before clonning: %v\n", team)
team_cloned := team.Clone()
fmt.Printf("original after clonning: %v\n", team)
fmt.Printf("clones slice: %v\n", team_cloned)
}
func (c *Team) Clone() Team {
var s = make(Team, len(*c))
copy(s, *c)
for index, _ := range s {
s[index].Name = "change name"
}
return s
}但是要小心,如果这个切片包含一个sub slice,那么需要进一步复制,因为我们仍然会让子片元素共享指向相同的内存块元素,一个例子是:
type Inventories []Inventory
type Inventory struct { //instead of: map[string]map[string]Pairs
Warehouse string
Item string
Batches Lots
}
type Lots []Lot
type Lot struct {
Date time.Time
Key string
Value float64
}
func main() {
ins := Inventory{
Warehouse: "DMM",
Item: "Gloves",
Batches: Lots{
Lot{mustTime(time.Parse(custom, "1/7/2020")), "Jan", 50},
Lot{mustTime(time.Parse(custom, "2/1/2020")), "Feb", 70},
},
}
inv2 := CloneFrom(c Inventories)
}
func (i *Inventories) CloneFrom(c Inventories) {
inv := new(Inventories)
for _, v := range c {
batches := Lots{}
for _, b := range v.Batches {
batches = append(batches, Lot{
Date: b.Date,
Key: b.Key,
Value: b.Value,
})
}
*inv = append(*inv, Inventory{
Warehouse: v.Warehouse,
Item: v.Item,
Batches: batches,
})
}
(*i).ReplaceBy(inv)
}
func (i *Inventories) ReplaceBy(x *Inventories) {
*i = *x
}https://stackoverflow.com/questions/39993688
复制相似问题