go - 推迟使用说明

标签 go deferred

假设我有以下功能

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/

相关文章:

go - BigQuery 中的数据库设计

Golang Gorilla CEX.IO Websocket 认证错误

javascript - $.when.apply 应用于 Promise 数组

javascript - 使用 Ajax Promise/Deferred

fortran - 在 Fortran 过程中可以有隐式种类

go - 在 go lang 中将字符串转换为 uint

function - 转到未定义的导入函数

Goroutine 存储 channel 值没有死锁

javascript - 如何让延迟处理程序将值返回给调用函数?

javascript - 如何确定所有文件已被读取并解决 promise