Skip to content

Instantly share code, notes, and snippets.

@leoleoasd
Last active April 8, 2022 19:16
Show Gist options
  • Save leoleoasd/0667c10f4c645e235eea8b068c74bf69 to your computer and use it in GitHub Desktop.
Save leoleoasd/0667c10f4c645e235eea8b068c74bf69 to your computer and use it in GitHub Desktop.
Simple hooks system in golang.
package main
import (
"fmt"
"reflect"
)
var hooks = map[string][]interface{}{}
func addHook(hook_name string, hook interface{}) {
hooks[hook_name] = append(hooks[hook_name], hook)
}
func runHook(hook_name string, args ...interface{}) [][]interface{} {
args_value := make([]reflect.Value, len(args))
for i, arg := range args {
args_value[i] = reflect.ValueOf(arg)
}
result := make([][]interface{}, len(hooks[hook_name]))
for i, hook := range hooks[hook_name] {
hook_func := reflect.ValueOf(hook)
rst := hook_func.Call(args_value)
result[i] = make([]interface{}, len(rst))
for j, v := range rst {
result[i][j] = v.Interface()
}
}
return result
}
func main() {
addHook("123", func(a int, b string) string { return fmt.Sprint(a, b) })
fmt.Print(runHook("123", 123, "123")[0][0].(string))
}
package main
import (
"testing"
"time"
)
func BenchmarkHooks(b *testing.B){
addHook("a", func(a int, b string, c time.Time) (int,string,time.Time) {return a,b,c})
t := time.Now()
b.ResetTimer()
for i:=0; i<b.N; i++ {
rst := runHook("a", 123,"aaa", t)[0]
_ = rst[0].(int)
_ = rst[1].(string)
_ = rst[2].(time.Time)
}
}
func BenchmarkFuncs(b *testing.B){
f := func(a int, b string, c time.Time) (int,string,time.Time) {return a,b,c}
t := time.Now()
b.ResetTimer()
for i:=0; i<b.N; i++ {
_,_,_ = f(123,"aaa", t)
}
}
@leoleoasd
Copy link
Author

Benchmark:

goos: darwin
goarch: amd64
pkg: test
BenchmarkHooks-16 632724 1740 ns/op
BenchmarkFuncs-16 1000000000 0.230 ns/op
PASS
ok test 1.482s

Hooks is 1580 times slower than regular function call.

@leoleoasd
Copy link
Author

A hooking call would take 1e-3 ms to run.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment