gpt4 book ai didi

go - 推迟使用说明

转载 作者:IT王子 更新时间:2023-10-29 01:49:19 26 4
gpt4 key购买 nike

假设我有以下功能

func printNumbers(){
var x int

defer fmt.Println(x)

for i := 0; i < 5; i++{
x++
}
}

正如specification中所说:

Each time a "defer" statement executes, the function value and parameters to the call are evaluated as usual and saved anew but the actual function is not invoked.

显然,函数执行结束时会打印出零。但是如果我想打印出变量x的最终值怎么办呢?

我想出了以下解决方案:

func printNumbers(){
var x int

printVal := func(){
fmt.Println(x)
}

defer printVal()

for i := 0; i < 5; i++{
x++
}
}

所以我想知道是否有更好的方法来解决这个问题。

最佳答案

一般来说,重要的是 x 不能作为您要延迟的函数的参数,因为它们是在执行 defer 时计算的。

1) 具有匿名功能

这是一个使用匿名函数的解决方案:

defer func() { fmt.Println(x) }()

这里的x不是延迟匿名函数的参数,所以不会被求值。仅当执行匿名函数并调用 fmt.Println() 时。

2) 带指针

使用指向 x 的指针(如 &x)会起作用,因为只评估地址,最后指向的值将是 5 当然。问题是 fmt.Println() 不会打印指向的值,而是打印指针本身。

但是为了演示它的工作原理,请看这个辅助函数:

func Print(i *int) {
fmt.Println(*i)
}

并使用它:

defer Print(&x) // Will print 5 at the end

3) 自定义类型

这类似于指针解决方案,但不需要辅助函数。但它确实需要您编写您的 String() 方法:

type MyInt int

func (m *MyInt) String() string {
return strconv.Itoa(int(*m))
}

并使用它:

var x MyInt

defer fmt.Println(&x)

for i := 0; i < 5; i++ {
x++
}

当执行defer 语句时,只会计算指针(x 的地址,*Myint 的类型)。由于 *MyInt 类型实现了 fmt.Stringer , fmt.Println() 会调用它的 String() 方法。

4) 包装

这也类似于指针解决方案,它甚至不会像您期望的那样只打印 5,但是:

#2 的问题是 fmt.Println() 将打印指针而不是指向的值(我们用自己的 Print() 函数解决了这个问题)。然而,还有其他类似于指针的类型,fmt.Println() 将打印它们的内容。

所以让我们将变量包装到一个 slice 中,看看会发生什么:

x := []int{0}

defer fmt.Println(x)

for i := 0; i < 5; i++ {
x[0]++
}

打印:

[5]

看到 5 的原因是 slice 是一个描述符。当 defer 被评估时,一个副本由 slice 组成(当它被执行时将被传递给 fmt.Println() )但它引用相同的底层数组.

另请注意,如果指针是指向结构、数组、 slice 、映射的指针,则 fmt.Println() 会打印指向的内容,因此以下代码也有效:

x := struct{ i int }{}

defer fmt.Println(&x)

for i := 0; i < 5; i++ {
x.i++
}

并打印:

&{5}

关于go - 推迟使用说明,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31404471/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com