【问题标题】:Change golang slice in another function在另一个函数中更改 golang 切片
【发布时间】:2019-10-23 05:50:00
【问题描述】:

我有一个切片,如果我直接在主函数中从中删除一个元素,切片的长度将减一。但是在另一个函数中删除并在main中调用它,切片的长度仍然保持原点。谁能给我解释一下?谢谢!

package main

import "fmt"

func main() {
    a := []int{1, 2, 3, 4}
    i := 0

    //copy(a[i:], a[i+1:])
    //a[len(a)-1] = 0
    //a = a[:len(a)-1]
    //fmt.Println(a)    //outputs: [2 3 4], this is correct

    f(a, i)
    fmt.Println(a) //outputs: [2 3 4 0], this is wrong!
}

func f(a []int, i int) {
    copy(a[i:], a[i+1:])
    a[len(a)-1] = 0
    a = a[:len(a)-1]
    fmt.Println(a) //outputs: [2 3 4], here still correct
}

Go Playground Link

【问题讨论】:

标签: go


【解决方案1】:

切片是按值传递的,因此在函数f 中更改它不会在函数main 中更改它。你可以通过指针传递,像这样:

package main

import "fmt"

func main() {
    a := []int{1, 2, 3, 4}
    i := 0

    f(&a, i)
    fmt.Println(a)    //outputs: [2 3 4], correct
}

func f(a *[]int, i int) {
    b := *a
    copy(b[i:], b[i+1:])
    // The following line seems pointless, but ok...
    b[len(b)-1] = 0
    b = b[:len(b)-1]
    fmt.Println(b)    //outputs: [2 3 4], here still correct
    *a = b
}

Go Playground

正如@zerkms 在 cmets 中所建议的,您还可以返回新切片,避免使用指针:

package main

import "fmt"

func main() {
    a := []int{1, 2, 3, 4}
    i := 0

    a = f(a, i)
    fmt.Println(a)
}

func f(a []int, i int) []int {
    copy(a[i:], a[i+1:])
    // The following line seems pointless, but ok...
    a[len(a)-1] = 0
    a = a[:len(a)-1]
    fmt.Println(a)     //outputs: [2 3 4], here still correct
    return a
}

【讨论】:

  • The slice is passed by value 不正确。切片通过引用传递。只是b[:len(b)-1]新建了一个切片,
  • @AyushGupta Go 中没有“通过引用传递”。
  • @AyushGupta Go golang.org/ref/spec 中没有“按引用传递”之类的东西,您的示例按值传递切片标头。
  • @AyushGupta 这里通过值传递的是切片头,所以函数获取了头的副本,这就是为什么改变头的副本,例如它的长度,没有反映在函数之外。
  • @AyushGupta 你错了; mkopriva 是对的。您必须了解 Go 中的任何内容都不会“通过引用传递”。某些类型具有像 semantics 这样的引用,但仍按值传递。
【解决方案2】:

没有提供新的解决方案,只是试图解释为什么你的程序会按照你的要求行事:

让我们先来了解一下内置函数‘copy’是如何工作的Ref: [https://golang.org/pkg/builtin/#copy]

func copy(dst, src []Type) int

copy 内置函数将元素从源切片复制到目标切片。 (作为一种特殊情况,它还将字节从字符串复制到字节片。)源和目标可能重叠。 Copy 返回复制的元素数量,它将是 len(src) 和 len(dst) 的最小值。

两件事: 1. 首先注释该行://a[len(a)-1] = 0

  1. 第二:当您使用相同的数组(即作为源和目标)时,您将得到 [2,3,4,4] 作为输出,因为目标数组是 {1,2,3,4},它被覆盖为 { 2,3,4,4(已经存在)}您可以尝试使用不同的数组以使您更清楚

【讨论】:

  • 感谢您没有提供新的解决方案。我知道副本最终会输出[2,3,4,4],所以我做了a = a[:len(a)-1]来缩短切片的长度。我认为关键不在于复制方法。我同意它们是按值传递的,因为我是 golang 的新手,所以我不知道它在低级别是如何工作的
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-10
  • 1970-01-01
  • 2018-02-28
  • 1970-01-01
  • 2012-09-27
  • 1970-01-01
相关资源
最近更新 更多