将指针传递给Go的延迟函数不起作用。

huangapple go评论85阅读模式
英文:

Pass pointer to go defer function doesn't work

问题

在我的代码中,我尝试使用numAddr来记录在defer语句之后num的变化。

func deferRun() {
    num := 1
    numAddr := &num
    defer fmt.Printf("num is %d", *numAddr)
    num = 2
    return
}

func main() {
    deferRun()
}

但是我得到的结果是num is 1,而不是2,为什么defer函数使用的是*numAddr的值而不是地址?

然后我尝试了另一种方式

func deferRun() {
    num := 1
    numAddr := &num
    defer func(intAddr *int){
        fmt.Printf("num is %d", *numAddr)
    }(numAddr)
    
    num = 2
    fmt.Println("num is", *numAddr)
    return
}

func main() {
    deferRun()
}

这次它起作用了,我得到了num is 2,所以我认为可能是defer fmt.Printf(something)在声明时立即存储了字符串,而当defer函数实际运行时并没有使用numAddr?

英文:

In my code I try to use numAddr to record the change of num after the defer statement

func deferRun() {
	num := 1
	numAddr := &num
	defer fmt.Printf("num is %d", *numAddr)
	num = 2
	return
}

func main() {
	deferRun()
}

but I get num is 1 instead of 2, why does the defer function use the value instead of address of *numAddr?

then I try another way

func deferRun() {
	num := 1
	numAddr := &num
	defer func(intAddr *int){
		fmt.Printf("num is %d", *numAddr)
	}(numAddr)
	
	num = 2
	fmt.Println("num is", *numAddr)
	return
}

func main() {
	deferRun()
}

This time it works and I get num is 2, so I think maybe defer fmt.Printf(something) stored the string immediately when it was declared and the numAddr is not used when the defer function actually run?

答案1

得分: 2

有趣的问题。为了回答这个问题,你必须了解一个规则,就像在这个Go教程中所说的那样:https://go.dev/tour/flowcontrol/12

延迟调用的参数会立即求值,但函数调用直到周围的函数返回时才执行。

示例1: 告诉延迟函数打印位于指定内存地址的值。

func deferRun() {
    num := 1
    numAddr := &num // 变量num在堆栈内存中的地址,例如0xc000076f38
    defer func(intAddr *int){
        fmt.Printf("num is %d", *numAddr)
    }(numAddr) // 嘿,Go,在周围的函数返回时,打印位于这个地址的值(numAddr=0xc000076f38)
    num = 2 // 现在位于地址0xc000076f38的值是2
    return  
}

输出将是2。

示例2: 告诉延迟函数打印指定的值。

func deferRun() {
    num := 1
    numAddr := &num // 变量num在堆栈内存中的地址,例如0xc000076f38
    defer fmt.Printf("num is %d", *numAddr) // 嘿,Go,在周围的函数返回时,打印这个值*numAddr(*numAddr现在是1)
    num = 2 // 现在位于地址0xc000076f38的值是2,但你告诉延迟函数在之前打印1
    return  
}

输出将是1。

英文:

Interesting question. To answer the question, you must know a rule, as in this Go tutorial https://go.dev/tour/flowcontrol/12

The deferred call's arguments are evaluated immediately, but the function call is not executed until the surrounding function returns..

Example 1: Telling the defer function to print value located in a specified memory address.

func deferRun() {
    num := 1
    numAddr := &num //address of variable num in stack memory, 0xc000076f38 for example
    defer func(intAddr *int){
        fmt.Printf("num is %d", *numAddr)
    }(numAddr) //Hey Go, when the surrounding function returns, print the value located in this address (numAddr=0xc000076f38)
    num = 2 //Now the value located in address 0xc000076f38 is 2
    return  
}

Output will be 2.

Example 2: Telling the defer function to print a specified value.

func deferRun() {
    num := 1
    numAddr := &num //address of variable num in stack memory, 0xc000076f38 for example
    defer fmt.Printf("num is %d", *numAddr) //Hey Go, when the surrounding function returns, print the this value *numAddr (*numAddr is 1 for now)
    num = 2 //Now the value located in address 0xc000076f38 is 2 but you told the defer function to print 1 before
    return  
}

Output will be 1.

huangapple
  • 本文由 发表于 2023年3月5日 15:09:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/75640684.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定