I have a *http.Request
, I call .Cookie("session")
on it, get back a possible cookie and a possible error. I handle it by just log.Fatal
ing it while I tool around, and I get http: named cookie not present
.
Makes sense, that is a perfectly expected error I want to handle. But what's the pattern for doing that? In Ruby, for example, it would throw an exception like CookieNotFound
and I would rescue CookieNotFound
and then explain what to do in that situation. Do I just need to call the Error()
function on the error, get the string, match against the string in a case statement, and copy logic between branches? I'd love some examples of well-handled errors.
As a side question: why is making things nil-able and passing separate possible errors around chosen over union types?
评论:
oscooter:
acln0:The http lib news up an instance of each type of error it will return and returns those. You can see here that the Cookie func will return the ErrNoCookie instance in the http package.
So you can check if it's a the cookie not present error by doing
if err == http.ErrNoCookie { // handle this specific error }
The documentation for the http package also shows some of the other errors the package can return.
Note that this can vary by package. The stdlib of go typically uses this method but other packages may expect you to do a type assertion on the error to check which type of error you got back.
Here's a handy article that explains the type assertion method in more depth.
mxxxz:The return value of the
Error() string
method is purely informative and should never be used for flow control.Errors come in a number of flavors and good libraries document the errors they return.
The first flavor is errors like
http.ErrNoCookie
,io.EOF
orbufio.ErrBufferFull
. Such errors are effectively constants and are usually namedErrSomething
. You check for them with simple equality:if err == http.ErrNoCookie { // do something }
Another flavor is like
net.OpError
,os.PathError
, orstrconv.NumError
, which represent a type of error rather than an exact error. These usually wrap an inner error with additional information. Such error types are usually namedSomethingError
. You check for such errors using a type assertion, like so:if perr, ok := err.(*os.PathError); ok { // use concrete information in perr }
Finally, you have interfaces like
net.Error
, which are desirable over concretely typed errors, because they reduce potential coupling between packages. Think of thenet.Error
interface as being a piece of documentation for optional methods the errors returned by packagenet
may have.If a type which implements
error
also implements aTimeout() bool
method, the caller need not know about the package the error came from or its concrete type. A check like this is sufficient:type timeouter interface { error Timeout() bool } if terr, ok := err.(timeouter); ok { // check terr.Timeout() }
is this handling equivalent of try-catch statements in Java?
