Skip to content

Instantly share code, notes, and snippets.

@imjasonh
Created December 2, 2015 19:25
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save imjasonh/190f7f7c7a76d35a2f54 to your computer and use it in GitHub Desktop.
Save imjasonh/190f7f7c7a76d35a2f54 to your computer and use it in GitHub Desktop.
Mad science: A method to take a func and args and give a channel that can be selected on. Useful (arguably) for timing out execution of a func.
package main
import (
"fmt"
"math/rand"
"reflect"
"time"
)
func main() {
select {
case ret := <-Func(func(s string, i int, b bool) string {
randSleep()
return fmt.Sprintln("values:", s, i, b)
}, "foo", 100, true):
fmt.Println("did not time out")
fmt.Printf("returned %q", ret)
case <-time.After(300 * time.Millisecond):
fmt.Println("timed out")
}
}
func Func(fn interface{}, args ...interface{}) <-chan interface{} {
fnv := reflect.ValueOf(fn)
if fnv.Kind() != reflect.Func {
panic("not a func")
}
fnt := reflect.TypeOf(fn)
if fnt.NumIn() != len(args) {
msg := fmt.Sprintf("incorrect number of args, got %d want %d", fnt.NumIn(), len(args))
panic(msg)
}
if fnt.NumOut() > 1 {
msg := fmt.Sprintf("incorrect number of return values, got %d want <= 1", fnt.NumOut())
panic(msg)
}
var vargs []reflect.Value
for _, a := range args {
vargs = append(vargs, reflect.ValueOf(a))
}
ch := make(chan interface{})
go func() {
ret := fnv.Call(vargs)
if len(ret) != 0 {
ch <- ret[0].Interface()
}
close(ch)
}()
return ch
}
// randSleep sleeps a random amount of time between 0-500ms
func randSleep() {
time.Sleep(time.Duration(rand.Intn(5)*100) * time.Millisecond)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment