Skip to content

Instantly share code, notes, and snippets.

@dannypsnl
Created June 21, 2018 17:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dannypsnl/c4f3198af8bf97ab7489cb075b8173b7 to your computer and use it in GitHub Desktop.
Save dannypsnl/c4f3198af8bf97ab7489cb075b8173b7 to your computer and use it in GitHub Desktop.
Go: Error is Value
package wrap
import (
"reflect"
)
type ErrorWrapper struct {
err error
prevReturns []reflect.Value
}
func NewErrorWrapper(vs ...interface{}) *ErrorWrapper {
args := make([]reflect.Value, 0)
// if no vs, nothing happened
for _, v := range vs {
args = append(args, reflect.ValueOf(v))
}
return &ErrorWrapper{
err: nil,
prevReturns: args,
}
}
func (w *ErrorWrapper) Then(task interface{}) *ErrorWrapper {
rTask := reflect.TypeOf(task)
// here reflect.Type.NumOut promise:
// 1. task is a function(else NumOut will panic)
// 2. < 1 mean, task has at least return 1 value
if rTask.NumOut() < 1 {
panic("at least return error at the end")
}
if w.err == nil {
vTask := reflect.ValueOf(task)
lenOfReturn := rTask.NumOut()
// reflect.Value.Call using []reflect.Value as it's arguments.
res := vTask.Call(w.prevReturns)
// res[lenOfReturn-1] mean error at here
//
// for example:
// Then(func() (string, error) { return "", nil })
//
// lenOfReturns = 2
// res[0] is string
// res[1] is error, 1 = lenOfReturns - 1
//
// this check is because when error = nil, it can't convert to type error
if res[lenOfReturn-1].Interface() != nil {
w.err = res[lenOfReturn-1].Interface().(error)
}
// prepare next task's arguments(when we want to passing some result to next task)
w.prevReturns = res[:lenOfReturn-1]
}
return w
}
// Final using catch handle the error generated by a task.
func (w *ErrorWrapper) Final(catch func(error)) {
if w.err != nil {
catch(w.err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment