Вы звоните код l.fixup(obj)
, несмотря ни на что.Если foo(bar, obj)
возвращает ошибку, выполняется некоторая обработка и вызывается l.fixup(obj)
- в противном случае вызывается только l.fixup(obj)
.Следовательно, ваш код может быть перестроен следующим образом:
// err will only be valid within the if-then-else-construct
if err := foo(bar, obj); err != nil {
// handle error from foo(bar,obj)
// you can even return it, if you wanted to
// For the sake of this example, we simply log it
log.Println("Executing foo: %s", err)
}
return l.fixup(obj)
Более того, вы можете использовать тот факт, что error
- это интерфейс для вашего преимущества, если вы хотите различить ошибку, потенциально возвращаемую foo
или l.fixup
.Вы можете сделать это, создав типизированную ошибку для одного (или обоих) и оценить тип ошибки, используя так называемый переключатель типа.
package main
import (
"errors"
"fmt"
)
// FooError is the error to be returned by foo
type FooError struct {
Bar string
}
// Error implements the interface
func (f FooError) Error() string {
return fmt.Sprintf("%s: interface is nil", f.Bar)
}
// dummy foo func
func foo(bar string, in interface{}) error {
if in == nil {
return FooError{Bar: bar}
}
return nil
}
// dummy fixup func
func fixup(in interface{}) error {
if in == nil {
return errors.New("Interface is nil")
}
return nil
}
// a wrapper, containing a variation of above code
func wrap(bar string) error {
if err := foo(bar, nil); err != nil {
// handle error from foo(bar,obj)
// you can even return it, if you wanted to
return err
}
return fixup(nil)
}
func main() {
err := wrap("test")
// The type switch itself
switch err.(type) {
case FooError:
// We have a FooError, so we can deal with it accordingly
fmt.Println("Foo Error:",err)
default:
// Every other error is handled by the default block
fmt.Println("Std Error:",err)
}
}
Однако это не совсем верно,Если вызывается foo
и возвращение ошибки предотвращает выполнение чего-либо еще в вашей логике , а не , вместо этого может быть допустимо паниковать.