• 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----
    ",
                    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
    ", 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
    ", 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 
    ", a, b, c)
        return a + b + c
    }
    
    func bar(a, b string) string {
        fmt.Printf("%s, %s 
    ", 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
  • 相关阅读:
    linux centos7 防止暴力破解
    win10 配置git 环境变量
    Tengine的说明
    php composer 报错 requires php ^7.1.8 || ^8.0 -> your php version
    uni-app v-for循环遍历 动态切换class、动态切换style
    Tomcat安装与配置
    我的云服务之WWW
    RHEL7 单独安装图形 X11
    python3-sql解析库——sqlparse
    Python3实战——爬虫入门
  • 原文地址:https://www.cnblogs.com/CherryTab/p/12826178.html
Copyright © 2020-2023  润新知