-
-
Save stevedonovan/bd660eec062b524eb4eb to your computer and use it in GitHub Desktop.
A general protected Go function caller using reflection.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Demonstrating a general protected call using reflection: | |
See http://golang.org/doc/go_spec.html#Handling_panics | |
*/ | |
package main | |
import ( | |
"fmt" | |
"reflect" | |
) | |
var println = fmt.Println | |
func add(a, b int) int { | |
return a + b | |
} | |
func answer() (first, second int) { | |
return 42,9 | |
} | |
func trouble(s string) { | |
println("ok so far",s) | |
panic("something bad happened") | |
} | |
func sum(values ...float64) float64 { | |
sum := 0.0 | |
for _,v := range(values) { | |
sum += v | |
} | |
return sum | |
} | |
func main() { | |
P := new(Protect) | |
var ok bool | |
var res Any | |
// can get multiple results with Callm, but | |
// you have to get the actual error from P | |
ok, res = P.Callm(answer) | |
if ! ok { | |
res = P.Error | |
} | |
println(ok,res) // res is an Any slice | |
// since you get Any back, need to cast to get actual result | |
ok, res = P.Call(add,10,20) | |
println(ok,res) | |
ires := res.(int) | |
println("result as integer",ires) | |
// variadic functions work fine, but need exact type | |
ok, res = P.Call(sum,10.0,20.0,30.0,40.0) | |
println(ok,res) | |
ok, res = P.Call(trouble,"hello") | |
println(ok,res) | |
// equivalent of try/catch | |
s := make([]int,3) | |
if ! P.Try(func() { | |
println(s[5]) // runtime error: index out of range | |
println("never get here") | |
}) { // and catch | |
println("error:",P.Error) | |
} | |
} | |
/// the Protect type //// | |
type Any interface{} | |
type Protect struct { | |
Error Any | |
} | |
func (self *Protect) Callm(fun Any, args ...Any) (status bool, results []Any) { | |
self.Error = nil | |
funv := reflect.ValueOf(fun) | |
if funv.Kind() != reflect.Func { | |
self.Error = "not a function" | |
return false,nil | |
} | |
defer func() { | |
if e := recover(); e != nil { | |
self.Error = e | |
} | |
}() | |
vargs := make([]reflect.Value,len(args)) | |
for i, a := range args { | |
vargs[i] = reflect.ValueOf(a) | |
} | |
resv := funv.Call(vargs) | |
res := make([]Any,len(resv)) | |
for i, v := range resv { | |
res[i] = v.Interface() | |
} | |
return true,res | |
} | |
func(self *Protect) Call(fun Any, args ...Any) (status bool, result Any) { | |
ok, results := self.Callm(fun,args...) | |
if ok { | |
if len(results) == 0 { | |
return true,nil | |
} else { | |
return true,results[0] | |
} | |
} | |
return false, self.Error | |
} | |
func(self *Protect) Try(fun Any) bool { | |
ok, _ := self.Callm(fun) | |
return ok | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment