Cleanup with defer
The reason defer exists is that a function has many exits and only one of them
is the last line. An early return, a return from inside a loop, a panic
three calls deeper: all of them have to release what the function acquired, and
writing the release once, next to the acquire, is the only version that stays
correct as the function grows.
f := open(path)
defer f.Close()
Two lines together, and the second one covers every path out. That pairing is the whole idiom, and it is why Go code puts the cleanup at the top of a function rather than the bottom.
Three things follow.
Cleanup runs during a panic. Deferred calls execute as the stack unwinds, so a resource is released even when the code that used it blew up.
Nested acquires release in reverse. Deferred calls are a stack, and reverse order is what you want: the inner thing goes away before the outer thing it depends on.
defer is scoped to the function, not to the block. A defer inside a
for loop does not run at the end of the iteration; it piles up and runs when
the whole function returns. If you need per-iteration cleanup, put the body in
its own function.
Task
Fill in the four functions in main.go. Each takes acquire and release as
function values, and the tests pass in a pair that records what happened.
WithResource(name, acquire, release, body)acquires, runsbody, releases on every path, and lets a panic inbodycontinue to the caller.EachResource(names, acquire, release, body)handles a whole slice, holding one resource at a time.Nested(acquire, release)acquiresoutertheninnerand releases them in reverse.TryUse(name, acquire, release, body) erroralways releases, and turns a panic inbodyinto an error"use <name>: <panic value>".
Hints
defer release(name)on the line afteracquire(name). Anything between the two is a leak waiting for its first early return.EachResourceis the loop trap: deferring inside the loop holds everything until the function ends, and the test checks the interleaving. One helper call per iteration fixes it, and you already wrote the helper.Nestedneeds no ordering logic. Defer both releases as you acquire and the stack reverses them for you.TryUsecombines this lesson with the last one: a named result, a deferredrecover, and the release deferred as well so it happens either way.- The panic value in
"use file: boom"is formatted with%v, sofmt.Errorf("use %s: %v", name, r)is the whole line.