Go的修饰器编程
学习自耗子叔
简单几个例子
package main import "fmt" func decorator(f func(s string)) func(s string) { return func(s string) { fmt.Println("started") f(s) fmt.Println("done") } } func hello(s string) { fmt.Println(s) } func main() { decorator(hello)("hello~~") }
这里主要是用了FuncForPC,这里在汇编中,就是根据指针获取func,然后就是defer的栈是在func返回前deferreturn的,所以一开始push进去的time参数就是执行func之前的时间
package main import ( "fmt" "reflect" "runtime" "time" ) type SumFunc func(int64, int64) int64 func getFunctionTime(i interface{}) string { return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name() } func timedSumFunc(f SumFunc) SumFunc { return func(start, end int64) int64 { defer func(t time.Time) { fmt.Printf("---Time Elapsed (%s): %v----\n", getFunctionTime(f), time.Since(t)) }(time.Now()) return f(start, end) } } func Sum1(start, end int64) int64 { var sum int64 sum = 0 if start > end { start, end = end, start } for i := start; i <= end; i++ { sum += i } return sum } func Sum2(start, end int64) int64 { if start > end { start, end = end, start } return (end - start + 1) * (end + start) / 2 } func main() { sum1 := timedSumFunc(Sum1) sum2 := timedSumFunc(Sum2) fmt.Printf("%d, %d\n", sum1(-10000, 10000000), sum2(-10000, 10000000)) }
有点类似于gin的hardware
package main import ( "fmt" "log" "net/http" "strings" ) func WithServerHeader(h http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { log.Println("--->WithServerHeader") w.Header().Set("Server", "HelloServer") h(w, r) } } func WithAuthCookie(h http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { log.Println("--->WithAuthCookie") cookie := &http.Cookie{Name:"Auth", Value:"Pass", Path:"/"} http.SetCookie(w, cookie) h(w, r) } } func WithBasicAuth(h http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { log.Println("--->WithBasicAuth") cookie, err := r.Cookie("Auth") if err != nil || cookie.Value != "Pass" { w.WriteHeader(http.StatusForbidden) return } h(w, r) } } func WithDebugLog(h http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { log.Println("--->WithDebugLog") r.ParseForm() log.Println(r.Form) log.Println("path", r.URL.Path) log.Println("schema", r.URL.Scheme) log.Println(r.Form["url_long"]) for k, v := range r.Form { log.Println("key: ", k) log.Println(v, strings.Join(v, "")) } h(w, r) } } func hello(w http.ResponseWriter, r *http.Request) { log.Printf("Recieved Request %s from %s\n", r.URL.Path, r.RemoteAddr) fmt.Fprintf(w, "Hello, World! "+r.URL.Path) } type HttpHandlerDecorator func(http.HandlerFunc) http.HandlerFunc func Handler(h http.HandlerFunc, decors ...HttpHandlerDecorator) http.HandlerFunc { for i := range decors { d := decors[len(decors)-1-i] h = d(h) } return h } func main() { // pipleline http.HandleFunc("/v1/hello", Handler(hello, WithAuthCookie, WithBasicAuth, WithDebugLog, WithServerHeader)) }
下面这个 Decorator()
需要两个参数,
- 第一个是出参
decoPtr
,就是完成修饰后的函数 - 第二个是入参
fn
,就是需要修饰的函数
package main import ( "fmt" "reflect" ) func Decorator(decoPtr, fn interface{}) (err error) { var decoratedFunc, targetFunc reflect.Value decoratedFunc = reflect.ValueOf(decoPtr).Elem() targetFunc = reflect.ValueOf(fn) v := reflect.MakeFunc(targetFunc.Type(), func(in []reflect.Value) (out []reflect.Value) { fmt.Println("before") out = targetFunc.Call(in) fmt.Println("after") return }) decoratedFunc.Set(v) return } func foo(a, b, c int) int { fmt.Printf("%d, %d, %d \n", a, b, c) return a + b + c } func bar(a, b string) string { fmt.Printf("%s, %s \n", a, b) return a + b } func main() { type MyFoo func(int, int, int) int var myfoo MyFoo Decorator(&myfoo, foo) myfoo(1, 2, 3) }
其实看起来蛮奇怪的,go马上要引入泛型,到那时应该会有舒适写法
https://coolshell.cn/articles/17929.html
end
一个没有高级趣味的人。
email:hushui502@gmail.com