Skip to content

Instantly share code, notes, and snippets.

@stevedonovan
Created September 8, 2011 07:40
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stevedonovan/bd660eec062b524eb4eb to your computer and use it in GitHub Desktop.
Save stevedonovan/bd660eec062b524eb4eb to your computer and use it in GitHub Desktop.
A general protected Go function caller using reflection.
/*
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