golang反射——実行関数

3322 ワード

golangフレームワークを書くときは、同様の方法で実行する必要があるという問題が避けられない.フレームワーク層はビジネス層の具体的な方法が不明であり、基本的な入出力フォーマットしか提供されていないため、ビジネス層の関数呼び出しに適した方法を使用する必要がある.
golangは反射を提供し、最終的に必要な2つの内容はTypeとValueです.反射により,new 1つのstructを実現したり,付与などの操作を実現したりすることができる.プログラムの処理は、別の方法で実現されると簡単に理解できる.これについて,golangの反射メカニズムを用いて関数の呼び出しを実現する方法に重点を置いた.
主なリファレンス
https://studygolang.com/articles/12348?fr=sidebar
https://jimmyfrasche.github.io/go-reflection-codex/#invoke-a-function
はい、下に出荷します.
package demo

import (
	"errors"
	"fmt"
	"reflect"
	"testing"
)

func hello() {
	fmt.Println("123")
}

func xixi(a int) (string, error) {
	fmt.Println(a)
	return "abc", nil
}

func haha(p ...int) (string, error) {
	fmt.Println(p)
	return "haha", errors.New("bad bad...")
}

type msg struct {
	name string
}

type specialMsg struct {
	msg
	age int
}

func lala(p ...int) (*msg, error) {
	fmt.Println(p)
	return &msg{
		name: "lalalaa",
	}, nil
}

func xaxa(a *msg) (string, error) {
	fmt.Println(a.name)
	return "ok", nil
}

func xaxa2(b *specialMsg) (string, error) {
	fmt.Println(b.name)
	return "lllala", nil
}

//    
func invoke(f interface{}, params ...interface{}) []reflect.Value {
	fv := reflect.ValueOf(f)
	realParams := make([]reflect.Value, len(params)) //  
	for i, item := range params {
		realParams[i] = reflect.ValueOf(item)
	}
	rs := fv.Call(realParams)
	return rs
}

func TestNewStudent(t *testing.T) {
	//     
	k := invoke(hello)
	fmt.Println(k)
	//      
	c := invoke(xixi, 12)
	fmt.Println(c)
	//      
	j := invoke(haha)
	fmt.Println(j)
	//       
	fmt.Printf(j[0].String())
	fmt.Printf(j[0].Kind().String())
	err := j[1].Interface().(error)
	if err != nil {
		fmt.Printf(err.Error())
	}
	m := invoke(lala, 1, 2, 3)
	fmt.Println(m[0].Pointer())
	fmt.Println(m[0].Kind().String())
	//       (      )
	rrr := m[0].Interface().(*msg)
	fmt.Println(rrr)
	fmt.Println(rrr.name)
	fmt.Println(m)

	tempP := &msg{
		name: "sdfdfdf",
	}
	ss := invoke(xaxa, tempP)
	fmt.Println(ss)
	tempSpecalMsg := &specialMsg{
		msg: msg{
			name: "aaaa",
		},
		age: 0,
	}
	ss2 := invoke(xaxa2, tempSpecalMsg)
	fmt.Println(ss2)
}

 
簡単に言えば,種々の関数に対する反射呼び出しを実現した.注意、ここは関数で、方法ではありません.方法は少し違います.上のいくつかの接続を参考にすることができます.
最後に注意すべきことを言います.
まずここのerrorですが、関数の戻り値をerrorと定義するには、Valueからerrorに変換することに注意する必要があります.直接変換する方法はなく、interface{}を得てからerrorに変換する必要があります.同様に、カスタムパラメータ、例えば構造体についても、まずinterface{}に変換し、その後、構造体に変換する必要があります.
実行結果:
GOROOT=/usr/local/go1.12.5 #gosetup
GOPATH=/Users/wuxueyou/gopath #gosetup
/usr/local/go1.12.5/bin/go test -c -o /private/var/folders/6q/swpkld2x38q9cqpkq75l18_80000gn/T/___TestNewStudent_in_study004_demo study004/demo #gosetup
/usr/local/go1.12.5/bin/go tool test2json -t /private/var/folders/6q/swpkld2x38q9cqpkq75l18_80000gn/T/___TestNewStudent_in_study004_demo -test.v -test.run ^TestNewStudent$ #gosetup
=== RUN   TestNewStudent
123
[]
12
[abc ]
[]
[haha ]
hahastringbad bad...[1 2 3]
824633982992
ptr
&{lalalaa}
lalalaa
[ ]
sdfdfdf
[ok ]
aaaa
[lllala ]
--- PASS: TestNewStudent (0.00s)
PASS

Process finished with exit code 0