追加在不存在的其他切片内部的结构上切片

时间:2018-10-15 19:24:22

标签: pointers go slice

例如:

package main

import "fmt"

type Test struct {
  elems []string
}

func main() {
  initial := Test{
    elems: make([]string, 0),
  }
  initial.elems = append(initial.elems, "apple")
  fmt.Println(initial.elems) // #1 [apple]

  s := make([]Test, 0)
  s = append(s, initial)

  initial.elems = append(initial.elems, "bannana")
  fmt.Println(initial.elems) // #2 [apple bannana]
  fmt.Println(s[0].elems) // #3 [apple]

  second := s[0]
  second.elems = append(second.elems, "carrot")
  fmt.Println(second.elems) // #4 [apple bannana]
}

我正在寻求帮助以了解打印声明#3和#4。在#3中,我期望[apple bannana];在#4中,我期望[apple bannana carrot]

据我了解,作为切片的elems字段是通过引用自动传递的,因此我在上述代码块中所做的每个追加都应修改基础数组。但是,显然不是这样。

所以,我的问题是:initial插入切片后会怎样呢?另外,如何编写此代码以在打印语句#4上获得预期结果?

2 个答案:

答案 0 :(得分:3)

在Golang中被提及:

  

映射和切片值的行为类似于指针:它们是   包含指向基础地图或切片数据的指针。复制地图或   切片值不会复制其指向的数据。

添加到切片s的方式是通过将Test结构的副本添加到s切片来创建新切片。因此,您没有设置指向原始Test结构的指针。这样,如果数据在结构内部发生变化,它也将反映在切片中。这是您面临的问题。

  initial.elems = append(initial.elems, "apple")
  fmt.Println(initial.elems) // #1 [apple]

  s := make([]Test, 0) // this should be pointer to the struct to have teh changes in future to original struct.
  s = append(s, initial) // appending to the s slice

在制作切片Test时创建指向s结构的指针,只要您更改原始结构中的元素,它就会反映出更改。例如:

package main
import "fmt"

type Test struct {
  elems []string
}

func main() {
  initial := Test{
    elems: make([]string, 0),
  }
  initial.elems = append(initial.elems, "apple")
  fmt.Println(initial.elems) // #1 [apple]

  s := make([]*Test, 0) // create a pointer to Test struct.
  s = append(s, &initial)

  initial.elems = append(initial.elems, "bannana")
  fmt.Println(initial.elems) // #2 [apple bannana]
  fmt.Printf("%+v\n",*s[0]) // #3 [apple banana]

  second := s[0]
  second.elems = append(second.elems, "carrot")
  fmt.Println(second.elems) // #4 [apple bannana carrot]
}

输出:-

[apple]
[apple bannana]
{elems:[apple bannana]}
[apple bannana carrot]

Go Playground上的工作代码

答案 1 :(得分:1)

这是由事实引起的,initial变量与s[0]不同-它们是两个独立的Test变量,追加到一个变量不会更改第二个变量。传递给initial时,append()被按值复制到另一个对象

证明:

fmt.Printf("second: %p, initial: %p\n", &second.elems[0], &initial.elems[0])

(其中second.elems[0] == "apple"initial.elems[0] == "apple") 输出

second: 0xc00000a120, initial: 0xc00000a0c0

这表明这是真的