传递给 Go 中的函数后更新切片

问题描述 投票:0回答:1

我想在 Go 中使用 defer,同时更新我在函数本身中传递的列表。

package main

import (
    "fmt"
    "time"
)

func record(start time.Time, l []int) {
    fmt.Printf("Record: Time: %v, List: %v\n", time.Since(start), l)
}

func record2(start time.Time, l ...int) {
    fmt.Printf("Record2: Time: %v, List: %v\n", time.Since(start), l)
}

func record3(start time.Time, l *[]int) {
    fmt.Printf("Record3: Time: %v, List: %v\n", time.Since(start), *l)
}

func main() {
    l := []int{1, 2, 3}

    defer func(t0 time.Time) {
        record(t0, l)
    }(time.Now()) // list updated

    defer record2(time.Now(), l...) // list not updated

    defer record3(time.Now(), &l) // list updated

    l = append(l, 4)
    time.Sleep(1 * time.Second)
    return
}

这回来了

Record3: Time: 1.001027459s, List: [1 2 3 4]
Record2: Time: 1.001204583s, List: [1 2 3]
Record: Time: 1.001209792s, List: [1 2 3 4]

但是在“Effective Go”here中提到方法3不是惯用的。

还有其他选择吗?

go pointers slice
1个回答
0
投票

他们的意思是使用数组不是惯用的,它与指向切片的指针无关:

func Sum(a *[3]float64) (sum float64) { ...

但即使这种风格也不是 Go 的惯用风格。使用切片代替。

实际上,slice 是一个包含 3 个字段的结构体:指向底层数组的指针、长度和容量。将切片传递给函数会复制此结构。如果您稍后通过添加元素来更改基础数组,则复制的结构上的长度和容量字段将不会反映这一点。因此,从函数内部来看,切片看起来就像没有改变一样。

查看示例此处

package main

import (
    "fmt"
    "time"
)

func byval(s []int) {
    time.Sleep(1)
    fmt.Printf("But in byval it appears the same: %v\n", s)
}

func byptr(s *[]int) {
    time.Sleep(2)
    fmt.Printf("While it. is actually changed, which is obvious in byptr: %v\n", s)
}

func main() {
    s := []int{1, 2, 3}
    go byval(s)
    go byptr(&s)
    s = append(s, 1)
    fmt.Printf("Slice was changed in main: %v\n", s)
    time.Sleep(3)
}

它打印以下内容:

Slice was changed in main: [1 2 3 1]
But in byval it appears the same: [1 2 3]
While it. is actually changed, which is obvious in byptr: &[1 2 3 1]

因此,使用指向数组的指针,它们是惯用的。

© www.soinside.com 2019 - 2024. All rights reserved.