go裝飾器


普通裝飾器(go中沒有python的@語法糖)

package main

import "fmt"

func user_logging(fun func()) func() func() {
    wrapper := func() func(){
        fmt.Println("this func is", fun)
        fmt.Println("the end of foo")
        return fun
    }
    return wrapper
}

func foo()  {
    println("i am foo")
}

func main() {
    foo := user_logging(foo)
    fmt.Println(foo())
}

//this func is 0x490840
//the end of foo
//0x490840
package main

import "fmt"

func user_logging(fun func()) func() { // 裝飾器函數
wrapper := func() {
fmt.Println("this func is", fun)
fun()
fmt.Println("the end of foo")
}
return wrapper
}

func foo() {
println("i am foo")
}

func main() {
foo := user_logging(foo)
foo()
}

//this func is 0x490840
//i am foo
//the end of foo

 

功能函數加參數

package main

import (
    "fmt"
    "time"
)

func show_time(fun func(...int)) func(...int) { // 裝飾器函數
    wrapper := func(args ...int) {
        start := time.Now().Unix()
        fun(args...)
        end := time.Now().Unix()
        fmt.Println(start, end)
        fmt.Printf("spend %d", end - start)
    }
    return wrapper
}

func add(args ...int)  {    // 功能函數
    sums := 0
    for _, v := range args {
        sums += v
    }
    fmt.Println(sums)
    time.Sleep(3 * time.Second)
}

func main() {
    add := show_time(add)
    add(1, 2, 3, 4, 5)
}

 

裝飾器函數加參數

package main

import (
    "fmt"
    "time"
)

func logger(flag bool) func(fun func(...int)) func(...int) {
    show_time := func(fun func(...int)) func(...int) { // 裝飾器函數
        wrapper := func(args ...int) {
            start := time.Now().Unix()
            fun(args...)
            end := time.Now().Unix()
            fmt.Println(start, end)
            fmt.Printf("spend %d\n", end - start)
            if flag == true {
                fmt.Println("日志記錄")
            }
        }
        return wrapper
    }
    return show_time
}


func add(args ...int)  {    // 功能函數
    sums := 0
    for _, v := range args {
        sums += v
    }
    fmt.Println(sums)
    time.Sleep(3 * time.Second)
}

func test() {
    show_time := logger(false)
    add := show_time(add)
    add(1, 2, 3, 4, 5)
}

func main() {
    show_time := logger(true)
    add := show_time(add)
    add(1, 2, 3, 4, 5)

    test()
}
//15
//1554351453 1554351456
//spend 3
//日志記錄

//15
//1554351456 1554351459
//spend 3

 

通過反射實現的通用型裝飾器

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")
args := []reflect.Value{}
if len(in) == 1 && in[0].Kind() == reflect.Slice {
for i := 0; i < in[0].Len(); i++ {
args = append(args, in[0].Index(i))
}
in = args
}
out = targetFunc.Call(in)
fmt.Println("after")
return
})

decoratedFunc.Set(v)
return
}

func foo(a, b, c int) int {
fmt.Println(a)
return b
}


func main() {
myfoo := foo
Decorator(&myfoo, foo)
myfoo(1, 2, 3)
}

//before
//1
//after

 對於以上實現的一個小坑,關於功能函數為定長和可變參數的區別

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")
            //args := []reflect.Value{}
            //if len(in) == 1 && in[0].Kind() == reflect.Slice {
            //    for i := 0; i < in[0].Len(); i++ {
            //        args = append(args, in[0].Index(i))
            //    }
            //    in = args
            //}                                // 定長參數                    可變參數
            fmt.Printf("%T\n", in) //[]reflect.Value             []reflect.Value
            fmt.Println(in) //[<int Value> <int Value> <int Value>]     [<[]int Value>]
            fmt.Printf("%T\n", in[0]) //reflect.Value             reflect.Value
            fmt.Println(in[0]) //                 1                         [1 2 3]
       // 可變參數的情況下,in是[<[]int Value>]而不是[<int Value> <int Value> <int Value>],[<[]int Value>]是不能直接傳入到Call函數中的  
// 所以需要將可變參數情況下,in [<[]int Value>]轉換成in []reflect.Value // 方法就是把<[]int Value>取出來即in[0],它的類型為reflect.Value,值為[1 2 3],所以使用in[0].Index(i)將其中的值一個個取出來,最后保存到[]reflect.Value中即可 out = targetFunc.Call(in) fmt.Println("after") return }) decoratedFunc.Set(v) return } func foo(args ...int) int { fmt.Println(args) return args[0] } func bar(a,b,c int) int { fmt.Println(a) return c } func main() { //myfoo := foo //Decorator(&myfoo, foo) //myfoo(1, 2, 3)

  mybar := bar
  Decorator(&mybar, bar)
  mybar(1,2,3)
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM