Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Golang Defer a closure

Tags:

closures

go

I am new to go and learning defer. I am wondering why the first one works while the second one not. I wonder what's the difference between them. First:

func say(s string) {
    defer func() {
        if  r := recover(); r != nil {
            fmt.Println("Recovered in cleanup:", r)
        }
        wg.Done()
    }()
    for i := 0; i < 3; i++ {
        fmt.Println(s)
        time.Sleep(time.Millisecond * 100)
        if i == 2 {
            panic("oh")
        }
    }
}

Second:

func cleanup(){
        if  r := recover(); r != nil {
            fmt.Println("Recovered in cleanup:", r)
        }
}

func say(s string) {
    defer func() {
        cleanup()
        wg.Done()
    }()
    for i := 0; i < 3; i++ {
        fmt.Println(s)
        time.Sleep(time.Millisecond * 100)
        if i == 2 {
            panic("oh")
        }
    }
}
like image 824
yan sun Avatar asked Sep 02 '25 10:09

yan sun


2 Answers

The specification says:

The return value of recover is nil if any of the following conditions holds:

...

  • recover was not called directly by a deferred function.

The cleanup() function is called by the anonymous deferred function. Rewrite the code to defer cleanup() directly.

func say(s string) {
    defer wg.Done()
    defer cleanup() // cleanup called directly by defer
    for i := 0; i < 3; i++ {
        fmt.Println(s)
        time.Sleep(time.Millisecond * 100)
        if i == 2 {
            panic("oh")
        }
    }
}

As per specification https://golang.org/ref/spec#Handling_panics

The return value of recover is nil if any of the following conditions holds:

  • panic's argument was nil
  • the goroutine is not panicking
  • recover was not called directly by a deferred function.

In your case recover was not directly called by deferred fuction.

like image 25
Pankaj Avatar answered Sep 04 '25 03:09

Pankaj