テンプレート システムは Go のリフレクト パッケージに大きく依存しています。このパッケージを使用する場合、インターフェイス上でメソッドを動的に呼び出す際に問題が発生する可能性があります。この問題は、データ型がインターフェースとして保存される場合に明らかになります。
インターフェースのメソッド呼び出しのダイナミクスを理解することが重要です。考慮すべきシナリオは 4 つあります。
リフレクションは、インターフェイスの基礎となるデータ値を決定するのに役立ちます。この情報を使用して、代替データ型を生成し、値受信メソッドとポインター受信メソッドを区別できます。
問題を解決するには、値とポインター表現の両方を作成する必要があります。データの:
value := reflect.ValueOf(data) if value.Type().Kind() == reflect.Ptr { ptr = value value = ptr.Elem() // acquire value referenced by pointer } else { ptr = reflect.New(reflect.TypeOf(i)) // create new pointer temp := ptr.Elem() // create variable to value of pointer temp.Set(value) // set value of variable to our passed in value }
両方のデータ型が利用可能な場合、メソッドの存在のチェックは次のようになります。簡単:
var finalMethod reflect.Value method := value.MethodByName(methodName) if method.IsValid() { finalMethod = method } // check for method on pointer method = ptr.MethodByName(methodName) if method.IsValid() { finalMethod = method } if (finalMethod.IsValid()) { return finalMethod.Call([]reflect.Value{})[0].String() }
このアプローチを採用すると、値またはポインター レシーバーとして定義されているかどうかに関係なく、任意のメソッドを効果的に動的に呼び出すことが可能になります。
package main import ( "fmt" "reflect" ) type Test struct { Start string } // value receiver func (t Test) Finish() string { return t.Start + "finish" } // pointer receiver func (t *Test) Another() string { return t.Start + "another" } func CallMethod(i interface{}, methodName string) interface{} { var ptr reflect.Value var value reflect.Value var finalMethod reflect.Value value = reflect.ValueOf(i) // if we start with a pointer, we need to get value pointed to // if we start with a value, we need to get a pointer to that value if value.Type().Kind() == reflect.Ptr { ptr = value value = ptr.Elem() } else { ptr = reflect.New(reflect.TypeOf(i)) temp := ptr.Elem() temp.Set(value) } // check for method on value method := value.MethodByName(methodName) if method.IsValid() { finalMethod = method } // check for method on pointer method = ptr.MethodByName(methodName) if method.IsValid() { finalMethod = method } if (finalMethod.IsValid()) { return finalMethod.Call([]reflect.Value{})[0].Interface() } // return or panic, method not found of either type return "" } func main() { i := Test{Start: "start"} j := Test{Start: "start2"} fmt.Println(CallMethod(i, "Finish")) fmt.Println(CallMethod(&i, "Finish")) fmt.Println(CallMethod(i, "Another")) fmt.Println(CallMethod(&i, "Another")) fmt.Println(CallMethod(j, "Finish")) fmt.Println(CallMethod(&j, "Finish")) fmt.Println(CallMethod(j, "Another")) fmt.Println(CallMethod(&j, "Another")) }
出力:
startfinish startfinish <nil> startanother startfinish startfinish <nil> startanother
以上がGo のインターフェイスでメソッドを動的に呼び出し、値レシーバとポインタ レシーバの両方を処理するにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。