恐慌:反映:调用reflect.Value.Call零值

时间:2017-02-02 05:54:06

标签: go reflection

我正在尝试使用反射来根据用户输入进行动态函数调用。我正在收集用户输入,如:

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”的参数。我希望“Meow [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

我该如何解决这个问题?还有,发生了什么?

3 个答案:

答案 0 :(得分:3)

您可能想要在使用之前检查reflect.ValueOf返回的内容。

在这种情况下,您将获得一个nil值,因为reflect无法看到未导出的函数。 hello以小写字母开头,因此不会导出。

另外,你在这里做了太多指点,我怀疑你需要做reflect.ValueOf(c)。你正在同时做太多事情。制作一个简单的工作示例并从那里继续调试。

这对我有用:https://play.golang.org/p/Yd-WDRzura

答案 1 :(得分:1)

只需在代码中进行两处更改即可。 首先改变reflect.ValueOf(& c)来反映.ValueOf(c) 其次改变reflect.ValueOf(命令)来反映.ValueOf(*命令)

这是代码workingcode

答案 2 :(得分:0)

您需要将 runCommandFromString 更改为 RunCommandFromString