Consider the following code:
type foo struct {
bar string
}
func f() *foo {
ret := &foo{"before"}
defer func() { ret.bar = "after" }()
return ret
}
func main() {
fmt.Println(f()) // prints "&{after}"
}
The motivation is having to return a struct but some of the fields need to be set only before returning (e.g. a timestamp of when the function completed).
Is deferring the field assignation a race condition? Is it idiomatic? Is there a better way?
The main benefit of using defer
statement versus invoking something before returning from a function or routine is defer
will run the statement even when a panic occurs before returning.
Thus it is commonly used to clean up resources (such as closing a file or network connection) rather than to set state.
The function below will not print or return "hello"
func f() string {
panic("omg")
fmt.Println("hello")
return "hello"
}
This code will print but won't return "hello"
func f() string {
defer fmt.Println("ello")
panic("omg")
return "hello"
}
To answer your question: No, it won't result in a race. Apart from the above difference, it is equivalent to calling something before the return
statement.
You mention timestamping when a function completes. In that case you can use defer
like this:
package main
import (
"fmt"
"time"
)
func main() {
foo()
}
func foo() {
defer trace("foo")()
time.Sleep(1 * time.Second)
}
func trace(fn string) func() {
start := time.Now()
return func() {
layout := "15:04:05.000"
end := time.Now()
fmt.Printf("%s start at %s, end at %s, total %s", fn, start.Format(layout), end.Format(layout), end.Sub(start))
}
}
Output: foo start at 23:00:00.000, end at 23:00:01.000, total 1s