Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Go 切片的内部操作是否影响原始切片的外部?_Go_Slice - Fatal编程技术网

Go 切片的内部操作是否影响原始切片的外部?

Go 切片的内部操作是否影响原始切片的外部?,go,slice,Go,Slice,例如: func test(requiredIp []int, i int) []int { requiredIp = append(requiredIp[0:i], requiredIp[i+1:]...) return requiredIp } func main(){ requiredIp := []int{1,2,4,5,6} fmt.Println(test(requiredIp,0)) // output:[2 4 5 6] fmt.Prin

例如:

func test(requiredIp []int, i int) []int {
    requiredIp = append(requiredIp[0:i], requiredIp[i+1:]...)
    return requiredIp
}

func main(){
    requiredIp := []int{1,2,4,5,6}
    fmt.Println(test(requiredIp,0)) // output:[2 4 5 6]
    fmt.Println("original", requiredIp) // output:[2 4 5 6,6]
}

为什么原始切片有两个6?

切片是一种结构类型,有三个字段:

  • 指向包含数据的底层数组(的地址)的指针
  • 长度-切片中有多少个元素
  • 容量—在不重新分配基础阵列的情况下,可以将多少元素存储到基础阵列中
当所有内容都在运行时,切片按值传递。当您将切片值分配给变量或在函数/方法调用中将其作为参数传递时,会发生这种情况。
由值(即复制)表示的是包含三个字段的结构。
复制的指针显然指向与原始切片中相同的数据块

代码中发生的情况如下所示:

  • 原始切片是
    []int{1,2,4,5,6}
    。 它的长度和容量等于5

  • 它被传递给一个函数,
    test

    通过函数的参数
    requiredIp
    获得的切片最初与调用中传递的切片相同

  • 通过计算
    requiredIp[0:i]
    重新切片,因为在调用
    i
    时等于0,所以计算
    requiredIp[0:0]

    该表达式使用支持数组和原始切片的容量以及长度0创建一个切片

  • 然后再次重新切片原始切片-使用表达式
    requiredIp[i+1://code>,在您的调用中是
    requiredIp[1://code>
    结果与原始结果共享备份数组,容量为4,内容为
    []int{2,4,5,6}

  • 然后,将上一步骤中获得的切片附加到上一步骤之前步骤中获得的切片上。这就是它变得有趣的地方

    假设要附加到原始切片第0个元素的点上的切片长度为0,容量为5。这意味着它可以容纳5种元素。
    也就是说,切片的支持数组仍然保持
    [1,2,4,5,6]

    被追加的切片与被追加的切片共享相同的支持数组,只是它指向第1个元素,而不是第0个元素

    append
    的代码看到它被告知要追加4个元素,并检查目标片是否有足够的容量容纳它们,并且它有。
    因此,
    append
    仅将
    [2,4,5,6]
    从同一个备份数组复制到同一个备份数组,覆盖其中从索引0开始的4个元素。实际上,它的元素
    [2,4,5,6]
    向左移动了一个元素

    生成的备份数组现在包含
    [2,4,5,6,6]
    :前4个元素是最后4个元素,向左移动一个元素,覆盖索引0到3处的内容

  • 现在,您将重播片段返回给调用者。该新切片值与示例中涉及的所有切片值共享备份数组,但请记住,它的长度设置为4-因为
    append
    将4个元素追加到长度为0的切片

  • 打印原始切片和从函数返回的切片。它们只在长度上有所不同:原始值等于5,函数返回的值为-到4。它们的其余字段是相同的:它们都有容量5,并通过指向第0个元素共享相同的支持数组。
    长度的差异解释了为什么“原始”切片中似乎有“额外的”
    6
    。事实上,在调用
    test
    之前,它的位置正好被省略了

  • 如果出于某种原因,您确实希望通过强制分配新的备份阵列将
    test
    生成的切片与原始切片“分离”,则有几种可能性:

    • 仅将附加到未分配的片上-例如,
      append([]int(nil),1,2,3,4)
      将分配一个新的后备数组

      在您的特定情况下,这并不像
      i>0
      那样是一个真正的解决方案,
      append
      必须在一个非空片上操作。对于exmaple,这可以通过两个附录来解决:

      s:=append([]int(nil),输入[0:i]…)
      s=追加(s,输入[i+1:]…)
      
      …或通过分配新切片和
      copy
      ing:

      s:=make([]int,len(输入)-1)
      复制,输入[0:i])
      复制(s[i:],输入[i+1:])
      
    • 重新选择原始切片时,请确保还人为地重置其容量:

      returnappend(输入[0:i:i],输入[i+1:]…)
      
      在这里,第一个片的容量与它的长度相同,
      i
      ,即使向它追加一个元素,也会迫使
      append
      分配一个新的后备数组,将这些
      i
      元素复制到它上面,然后复制所追加的内容

    进一步阅读:


  • ……实际上考虑开始。

    切片由数组支持,并且尽可能地将原始数组的副本共享,使数组首先被分配。我们可以使用
    z:=test(requiredIp,0)显示test函数返回的切片包含所有值;fmt.Println(z[:5])
    对于切片,索引上限是切片容量上限(a),而不是长度