Go 切片是否按值传递?

Go 切片是否按值传递?,go,slice,pass-by-value,Go,Slice,Pass By Value,在围棋中,我试图为我的旅行推销员问题制作一个置乱切片函数。在这样做的时候,我注意到当我开始编辑切片时,每次传入时,我给出的置乱函数都是不同的 经过一些调试,我发现这是由于我编辑了函数中的片段。但既然Go应该是一种“传递值”语言,这怎么可能呢 我提供了一个游乐场链接来说明我的意思。 通过删除第27行,您得到的输出与保留该行不同,这不应该有什么区别,因为当作为参数传入时,函数应该创建自己的切片副本。 有人能解释这种现象吗?围棋中的所有东西都是按值传递的。但是切片值是一个头,描述了一个支持数组的连续

在围棋中,我试图为我的旅行推销员问题制作一个置乱切片函数。在这样做的时候,我注意到当我开始编辑切片时,每次传入时,我给出的置乱函数都是不同的

经过一些调试,我发现这是由于我编辑了函数中的片段。但既然Go应该是一种“传递值”语言,这怎么可能呢

我提供了一个游乐场链接来说明我的意思。 通过删除第27行,您得到的输出与保留该行不同,这不应该有什么区别,因为当作为参数传入时,函数应该创建自己的切片副本。

有人能解释这种现象吗?

围棋中的所有东西都是按值传递的。但是切片值是一个头,描述了一个支持数组的连续部分,切片值只包含一个指向实际存储元素的数组的指针。切片值不包括其元素(与数组不同)

因此,当您将一个切片传递给函数时,将从此头创建一个副本,其中包括指向同一后备数组的指针。修改切片的元素意味着修改备份数组的元素,因此共享同一备份数组的所有切片都将“观察”更改

要查看切片标头中的内容,请检查类型:

见相关/可能重复的问题:


阅读博客帖子:

当它被传递时,它被传递到底层数组的指针,所以a是一个指向底层数组的小结构。小结构被复制,但它仍然指向相同的底层数组。包含切片元素的内存块通过“引用”传递。保存容量、元素数和元素指针的切片信息三元组按值传递

处理传递给函数的切片的最佳方法(如果切片的元素被操纵到函数中,并且我们不希望这反映在元素内存块中,则使用
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
}
但是要小心,如果此片包含
子片
,则需要进一步复制,因为我们仍然会让子片元素共享指向相同的内存块元素,例如:

type Inventory[]存货
键入清单结构{//而不是:map[string]map[string]Pairs
仓库串
项目字符串
批量
}
类型批次[]批次
类型批结构{
日期时间,时间
键串
值浮动64
}
func main(){
ins:=存货{
仓库:“DMM”,
物品:“手套”,
批次:批次{
标段{mustTime(time.Parse(自定义,“1/7/2020”),“Jan”,50},
标段{mustTime(time.Parse(自定义,“2/1/2020”),“Feb”,70},
},
}
inv2:=克隆源(c存货)
}
func(i*存货)克隆自(c存货){
存货:=新的(存货)
对于u,v:=范围c{
批次:=批次{}
对于u,b:=范围v.批次{
批次=追加(批次、批次){
日期:b.日期,
钥匙:b.钥匙,
价值:b.价值,
})
}
*存货=追加(*存货,存货{
仓库:v.仓库,
项目:五、项目,
批次:批次,
})
}
(*i).替换人(投资部)
}
func(i*存货)替换为(x*存货){
*i=*x
}

您可以在下面找到一个示例。简单地说,切片也会按值传递,但原始切片和复制的切片链接到同一基础数组。如果此切片中的一个发生更改,则基础数组会发生更改,然后其他切片也会发生更改

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)
}
主程序包
输入“fmt”
func main(){
x:=[]整数{1,10,100,1000}
双(x)
fmt.Println(x)/--->3将打印[2,20,200,2000](原始切片已更改)
}
func double(y[]int){
fmt.Println(y)/--->1将打印[1,10,100,1000]
对于i:=0;i2将打印[2,20,200,2000](数组下的复制片+已更改)
}

为了补充这篇文章,下面是一个通过引用传递您所共享内容的示例:

type point struct {
    x int
    y int
}

func main() {
    data := []point{{1, 2}, {3, 4}, {5, 6}, {7, 8}}
    makeRandomDatas(&data)
}

func makeRandomDatas(dataPoints *[]point) {
    for i := 0; i < 10; i++ {
        if len(*dataPoints) > 0 {
            fmt.Println(makeRandomData(dataPoints))
        } else {
            fmt.Println("no more elements")
        }
    }

}

func makeRandomData(cities *[]point) []point {
    solution := []point{(*cities)[0]}                 //create a new slice with the first item from the old slice
    *cities = append((*cities)[:0], (*cities)[1:]...) //remove the first item from the old slice
    return solution

}
类型点结构{
x int
y整数
}
func main(){
数据:=[]点{{1,2},{3,4},{5,6},{7,8}
生成随机数据(&data)
}
func生成随机数据(数据点*[]点){
对于i:=0;i<10;i++{
如果len(*数据点)>0{
fmt.Println(生成随机数据(数据点))
}否则{
fmt.Println(“无更多元素”)
}
}
}
func makeRandomData(城市*[]点)[]点{
解决方案:=[]点{(*城市)[0]}//使用旧切片中的第一项创建新切片
*cities=append((*cities)[:0],(*cities)[1:]…)//从旧切片中删除第一项
返回溶液
}

因此,解决方案是在函数中创建切片的本地副本。并对其进行编辑吗?@user4901806,如果您不想修改所传递切片的元素(它指向的支持数组的元素),然后是,复制。@因为切片标头包含长度。如果附加元素,则长度必须增加,因此,即使备份数组有空间容纳此附加元素,并且没有分配新的备份数组,也不会复制现有元素,原始切片标头也不会“看到”它。这就是内置
append()
函数必须返回一个新的切片值。更不用说是否必须分配一个新数组…@vas
type Container struct{data[]byte}
不是嵌入,它只是一个常规字段。如果只有一个字段,则答案是肯定的。如果有多个字段,则可能会应用隐式填充,因此整个结构的大小可能会更大。@vas是的,无论使用嵌入还是命名字段,它们都使用相同的内存量。
type point struct {
    x int
    y int
}

func main() {
    data := []point{{1, 2}, {3, 4}, {5, 6}, {7, 8}}
    makeRandomDatas(&data)
}

func makeRandomDatas(dataPoints *[]point) {
    for i := 0; i < 10; i++ {
        if len(*dataPoints) > 0 {
            fmt.Println(makeRandomData(dataPoints))
        } else {
            fmt.Println("no more elements")
        }
    }

}

func makeRandomData(cities *[]point) []point {
    solution := []point{(*cities)[0]}                 //create a new slice with the first item from the old slice
    *cities = append((*cities)[:0], (*cities)[1:]...) //remove the first item from the old slice
    return solution

}