web-dev-qa-db-ja.com

GoでStructとそのメソッドを名前で呼び出しますか?

私はここに関数呼び出し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()にそれを使用します、それでいいですか?

29
nvcnvn

オブジェクトのメソッドを呼び出すには、最初に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{})
}
49
user811773
_  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」の入力パラメーターの数が引数の長さと等しいことを確認してください
  4. retreflect.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(NotAnShape{}, "ForBar") 
_

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

コンパイル時にどの最初のタイプが使用されるかわからない場合は、次のように、可能なすべてのタイプを格納するマップを作成できます。

_    map[string]reflect.Value{
            "YourT1" : reflect.ValueOf(YourT1{})
            "YourT2" : reflect.ValueOf(YourT2{})
            "Circle" : reflect.ValueOf(Cirlce{}) // or reflect.ValueOf(&Circle{})
    }  
_
19
snyh

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
}
2
Ramil Gilfanov
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)
}
0
Hao