我想在 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不是惯用的。
还有其他选择吗?
他们的意思是使用数组不是惯用的,它与指向切片的指针无关:
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]
因此,使用指向数组的指针,它们是惯用的。