ユーザー入力に基づいて動的な関数呼び出しを行うために、リフレクションを使用しようとしています。私はそのようなユーザー入力を収集しています:
func main() {
for {
reader := bufio.NewReader(os.Stdin)
fmt.Print("> ")
command, _ := reader.ReadString('\n')
runCommandFromString(command)
}
}
これは、コマンドが解析される方法です
func stringCommandParser(cmd string) *Command {
cmdParts := strings.Split(
strings.TrimSpace(cmd),
" ",
)
return &Command{
Name: cmdParts[0],
Args: cmdParts[1:],
}
}
func runCommandFromString(cmd string) {
command := stringCommandParser(cmd)
c := &Commander{}
f := reflect.ValueOf(&c).MethodByName(command.Name)
inputs := []reflect.Value{reflect.ValueOf(command)}
f.Call(inputs)
}
Commands.goファイルは次のようになります
type Command struct {
Name string
Args []string
}
type Commander struct {}
func (c Commander) Hello(cmd Command) {
fmt.Println("Meow", cmd.Args)
}
プログラムを実行すると、プロンプトが表示され、「Hello」というコマンドを「world」というパラメーターで実行します。 「ニャー[ワールド]」みたいなものが出てくると思います。このような:
> Hello world
Meow world
代わりに、私が得るのは次のようなパニックです:
> Hello world
panic: reflect: call of reflect.Value.Call on zero Value
goroutine 1 [running]:
panic(0x123360, 0xc420014360)
/Users/parris/.gvm/gos/go1.7.4/src/runtime/panic.go:500 +0x1a1
reflect.flag.mustBe(0x0, 0x13)
/Users/parris/.gvm/gos/go1.7.4/src/reflect/value.go:201 +0xae
reflect.Value.Call(0x0, 0x0, 0x0, 0xc420055e00, 0x1, 0x1, 0x0, 0x0, 0x0)
/Users/parris/.gvm/gos/go1.7.4/src/reflect/value.go:300 +0x38
main.runCommandFromString(0xc42000c8a0, 0xc)
/Users/parris/Projects/distro/main/utils.go:26 +0x1a0
main.main()
/Users/parris/Projects/distro/main/main.go:14 +0x149
exit status 2
どうすれば修正できますか?また、何が起こっていますか?
使用する前に、_reflect.ValueOf
_が返すものを確認することをお勧めします。
この場合、reflectはエクスポートされていない関数を見ることができないため、nil値を取得しています。 hello
は小文字で始まるため、エクスポートされません。
また、ここではポインタの数が多すぎます。reflect.ValueOf(c)
を実行する必要があると思います。同時に多くのことを実行してデバッグしています。簡単な作業例を作成し、そこからデバッグを続行します。
これは私にとってはうまくいきます: https://play.golang.org/p/Yd-WDRzura
コードに2つの変更を加えるだけです。最初にreflect.ValueOf(&c)をreflect.ValueOf(c)に変更します。次にreflect.ValueOf(command)をreflect.ValueOf(* command)に変更します。
これはコードです workingcode