【问题标题】:passing slice as a reference to reflect changes in caller [duplicate]传递切片作为参考以反映调用者的变化[重复]
【发布时间】:2019-05-19 16:53:18
【问题描述】:

main 声明了一个名称为 allOutputs 的切片(我相信它是字符串切片,而不是字符串数组),长度为零,容量为 100。然后它附加一个值为“abcd”的字符串并调用 myTest 函数,该函数将数组 [0] 更新为“1234”,然后附加一个值为“5678”。

当我在调用myTest 之后打印allOutputs 时,我正确地看到第一个索引处的元素具有更新值“1234”。这告诉我 myTest 得到 slice 作为参考。但是后来的"5678"append 根本没有被调用者(这里主要)看到,为什么会这样?请记住,原始切片由容量为 100 的数组支持。为什么当切片通过引用传递时,我在 main 中看不到 5678?

换句话说,追加究竟是如何工作的?

import "fmt"

func myTest(array []string) {
    array[0] = "1234"
    array = append(array, "5678")
}

func main() {
    allOutputs := make([]string, 0, 100)
    allOutputs = append(allOutput, "abcd")
        fmt.Println(allOutputs) // Println1
    myTest(allOutputs)
    fmt.Println(allOutputs) // Println2
}

实际输出: [1234]

我预计: [1234, 5678]

【问题讨论】:

  • 没有“通过引用”,所以我不确定你从哪里得到的。您只是传递切片值,它是一个副本,不会更改原始值。
  • 当你传递一个 slice 时,Go 传递一个 slice header 的副本。这就解释了为什么 array[0] = "1234"。您仍然可以访问和提醒底层阵列对象。另一方面,append 创建切片和底层数组的副本,因为myTest 函数没有返回它,所以您看不到main 中的更改。当我开始查看 slice 时,我发现 github.com/golang/go/wiki/SliceTricks 非常有用。

标签: arrays go append slice


【解决方案1】:

append 完全按照您的想法工作!

正如您在this playground 中所见,如果您不将allOutputs 数组作为参数传递给myTestappend 函数将按预期工作。

正如您所怀疑的,append 可能在超过原始数组的容量时返回一个新数组。在您的示例中,myTest 中的数组大小修改,但是,它是 allOutputs 的副本,保持不变。

最好把数组想象成一个字符串。它是一个可变的内存块。当作为参数传递时,会复制整个块。

您的假设是正确的,因为数组 allOutputs 预先分配了 100 个元素,因此对 append 的调用不需要更改 array

如果你写了this,你会看到你预期的结果。

allOutputs := make([]string, 0, 100)
allOutputs = append(allOutputs, "abcd")
fmt.Println(allOutputs) // Println1
allOutputs[0] = "1234"
allOutputs = append(allOutputs, "5678")
fmt.Println(allOutputs) // Println2

一个很好的解决方案是:

   type myStrings []string

   func (m *mystring) myTest() {
      // Do something
   }

如果您声明自己的类型,那么您可以定义一个无需显式使用 & 运算符就可以改变数组的方法。

【讨论】:

    猜你喜欢
    • 2019-08-12
    • 2016-10-27
    • 2014-10-09
    • 2023-03-24
    • 1970-01-01
    • 1970-01-01
    • 2013-06-30
    • 2016-12-15
    • 2013-06-22
    相关资源
    最近更新 更多