@@ -165,7 +165,7 @@ methods:
165165
166166<a id="naming-doubles"></a>
167167
168- ### Test double packages and types
168+ ### Test double and helper packages
169169
170170There are several disciplines you can apply to [naming] packages and types that
171171provide test helpers and especially [test doubles]. A test double could be a
@@ -1241,11 +1241,47 @@ Another case in which panics can be useful, though uncommon, is as an internal
12411241implementation detail of a package which always has a matching recover in the
12421242callchain. Parsers and similar deeply nested, tightly coupled internal function
12431243groups can benefit from this design, where plumbing error returns adds
1244- complexity without value. The key attribute of this design is that these panics
1245- are never allowed to escape across package boundaries and do not form part of
1246- the package's API. This is typically accomplished with a top-level deferred
1247- recover that translates a propagating panic into a returned error at the public
1248- API surfaces.
1244+ complexity without value.
1245+
1246+ The key attribute of this design is that these ** panics are never allowed to
1247+ escape across package boundaries** and do not form part of the package's API.
1248+ This is typically accomplished with a top-level deferred function that uses
1249+ ` recover ` to translate a propagated panic into a returned error at the public
1250+ API boundary. It requires the code that panics and recovers to distinguish
1251+ between panics that the code raises itself and those that it doesn't:
1252+
1253+ ``` go
1254+ // Good:
1255+ type syntaxError struct {
1256+ msg string
1257+ }
1258+
1259+ func parseInt (in string ) int {
1260+ n , err := strconv.Atoi (in)
1261+ if err != nil {
1262+ panic (&syntaxError{" not a valid integer" })
1263+ }
1264+ }
1265+
1266+ func Parse (in string ) (_ *Node , err error ) {
1267+ defer func () {
1268+ if p := recover (); p != nil {
1269+ sErr , ok := p.(*syntaxError)
1270+ if !ok {
1271+ panic (p) // Propagate the panic since it is outside our code's domain.
1272+ }
1273+ err = fmt.Errorf (" syntax error: %v " , sErr.msg )
1274+ }
1275+ }()
1276+ ... // Parse input calling parseInt internally to parse integers
1277+ }
1278+ ```
1279+
1280+ > ** Warning:** Code employing this pattern must take care to manage any
1281+ > resources associated with the code run in such defer-managed sections (e.g.,
1282+ > close, free, or unlock).
1283+ >
1284+ > See: [ Go Tip #81 : Avoiding Resource Leaks in API Design]
12491285
12501286Panic is also used when the compiler cannot identify unreachable code, for
12511287example when using a function like ` log.Fatal ` that will not return:
@@ -1270,6 +1306,16 @@ If you must die in a package initialization function (an `init` or a
12701306[ "must" function] ( decisions#must-functions ) ), a panic is acceptable in place of
12711307the fatal logging call.
12721308
1309+ See also:
1310+
1311+ * [ Handling panics] ( https://go.dev/ref/spec#Handling_panics ) and
1312+ [ Run-time Panics] ( https://go.dev/ref/spec#Run_time_panics ) in the language
1313+ specification
1314+ * [ Defer, Panic, and Recover] ( https://go.dev/blog/defer-panic-and-recover )
1315+ * [ On the uses and misuses of panics in Go] ( https://eli.thegreenplace.net/2018/on-the-uses-and-misuses-of-panics-in-go/ )
1316+
1317+ [ Go Tip #81: Avoiding Resource Leaks in API Design ] : https://google.github.io/styleguide/go/index.html#gotip
1318+
12731319<a id =" documentation " ></a >
12741320
12751321## Documentation
0 commit comments