38

MethodByName()ここhttp://golang.org/pkg/reflect/#Value.MethodByNameで関数呼び出しを見つけましたが、それは私が望んでいるものではありません。(多分それを使う方法がわからないので...私はそれでどんな例も見つけることができません)。私が欲しいのは:

type MyStruct struct {
//some feilds here
} 
func (p *MyStruct) MyMethod { 
    println("My statement."); 
} 

CallFunc("MyStruct", "MyMethod"); 
//print out "My statement." 

だから、まずは次のようなものが必要だと思いますがStructByName()、その後はそれを使ってMethodByName()くださいね!?

4

4 に答える 4

68

オブジェクトのメソッドを呼び出すには、最初にを使用しますreflect.ValueOf。次に、名前でメソッドを見つけ、最後に見つかったメソッドを呼び出します。例えば:

package main

import "fmt"
import "reflect"

type T struct {}

func (t *T) Foo() {
    fmt.Println("foo")
}

func main() {
    var t T
    reflect.ValueOf(&t).MethodByName("Foo").Call([]reflect.Value{})
}
于 2011-11-12T17:49:58.890 に答える
31
type YourT1 struct {}
func (y YourT1) MethodBar() {
    //do something
}

type YourT2 struct {}
func (y YourT2) MethodFoo(i int, oo string) {
    //do something
}

func Invoke(any interface{}, name string, args... interface{}) {
    inputs := make([]reflect.Value, len(args))
    for i, _ := range args {
        inputs[i] = reflect.ValueOf(args[i])
    }
    reflect.ValueOf(any).MethodByName(name).Call(inputs)
}

func main() {
     Invoke(YourT2{}, "MethodFoo", 10, "abc")
     Invoke(YourT1{}, "MethodBar")
}

実際、コードはメソッドの入力番号をチェックする必要があり、メソッド自体が存在するかどうかさえもチェックする必要があります。

このhttp://gowalker.org/reflect#Typeを参照できます

  1. 「any」が構造体タイプであることを確認してください
  2. 「any」に「name」メソッドがあることを確認してください
  3. メソッド「name」の入力パラメーターの数がargsの長さと等しいことを確認してください
  4. によって実装retするreflect.Value.Interface()

Ptrタイプに注意してください。

またはSomeInterface{}、直接使用する代わりに、次のinterface{}ようにこの「任意の」タイプを確保するために使用できます。

type Shape interface {
    Area() float64  //some method to ensure any is an Shape type.
}

func Invoke(s Shape, name string, inputs...interface{}) []interface{} {
}

だからこれは大丈夫です

color := Invoke(Circle{}, "GetColor")[0].(Color)

しかし

Invoke(NotAShape{}, "ForBar")

NotAnShapeはシェイプではないため、コンパイルできません。

コンパイル時に最初のタイプについて確信が持てない場合は、次のように、考えられるすべてのタイプを格納するマップを作成できます。

map[string]reflect.Value{
    "YourT1" : reflect.ValueOf(YourT1{})
    "YourT2" : reflect.ValueOf(YourT2{})
    "Circle" : reflect.ValueOf(Cirlce{}) // or reflect.ValueOf(&Circle{})
}  
于 2013-11-01T05:57:02.550 に答える
2

gist はエラー処理でstructメソッドを呼び出します

// Invoke - firstResult, err := Invoke(AnyStructInterface, MethodName, Params...)
func invoke(any interface{}, name string, args ...interface{}) (reflect.Value, error) {
    method := reflect.ValueOf(any).MethodByName(name)
    methodType := method.Type()
    numIn := methodType.NumIn()
    if numIn > len(args) {
        return reflect.ValueOf(nil), fmt.Errorf("Method %s must have minimum %d params. Have %d", name, numIn, len(args))
    }
    if numIn != len(args) && !methodType.IsVariadic() {
        return reflect.ValueOf(nil), fmt.Errorf("Method %s must have %d params. Have %d", name, numIn, len(args))
    }
    in := make([]reflect.Value, len(args))
    for i := 0; i < len(args); i++ {
        var inType reflect.Type
        if methodType.IsVariadic() && i >= numIn-1 {
            inType = methodType.In(numIn - 1).Elem()
        } else {
            inType = methodType.In(i)
        }
        argValue := reflect.ValueOf(args[i])
        if !argValue.IsValid() {
            return reflect.ValueOf(nil), fmt.Errorf("Method %s. Param[%d] must be %s. Have %s", name, i, inType, argValue.String())
        }
        argType := argValue.Type()
        if argType.ConvertibleTo(inType) {
            in[i] = argValue.Convert(inType)
        } else {
            return reflect.ValueOf(nil), fmt.Errorf("Method %s. Param[%d] must be %s. Have %s", name, i, inType, argType)
        }
    }
    return method.Call(in)[0], nil
}
于 2018-11-14T04:22:27.753 に答える
0
package main

import (
    "fmt"
    "reflect"
)

type Log struct {
    Path  string
    Level string
}

func (l *Log) Conversion(i interface{}) {

    if data, ok := i.(*Log); ok {
        if data != nil {
            if len(data.Path) > 0 {
                l.Path = data.Path
            }
            if len(data.Level) > 0 {
                l.Level = data.Level
            }
        }
    }
}

type Storage struct {
    Type       string
    ServerList []string
}

func (s *Storage) Conversion(i interface{}) {

   if data, ok := i.(*Storage); ok {
        if data != nil {
            if len(data.Type) > 0 {
                s.Type = data.Type
            }
        }
    }
}

type Server struct {
    LogConfig     *Log
    StorageConfig *Storage
}

func main() {
    def := Server{
        LogConfig: &Log{
            Path:  "/your/old/log/path/",
            Level: "info",
        },
        StorageConfig: &Storage{
            Type:       "zookeeper",
            ServerList: []string{"127.0.0.1:2181"},
        },
    }

    fmt.Println(def)
    cur := Server{
        LogConfig: &Log{
            Path:  "/your/new/log/path/",
            Level: "debug",
        },
        StorageConfig: &Storage{
            Type:       "etcd",
            ServerList: []string{"127.0.0.1:2379"},
        },
    }

    fmt.Println(cur)

    defV := reflect.ValueOf(def)
    curV := reflect.ValueOf(cur)
    for k := 0; k < defV.NumField(); k++ {
        in := make([]reflect.Value, 1)
        in[0] = reflect.ValueOf(curV.Field(k).Interface())
        defV.Field(k).MethodByName("Conversion").Call(in)
    }

    fmt.Println(def.LogConfig)
    fmt.Println(def.StorageConfig)
}
于 2019-01-08T13:01:48.970 に答える