Go语言 恐慌:反映:调用reflect.Value,调用零值

wbrvyc0a  于 2023-03-16  发布在  Go
关注(0)|答案(5)|浏览(221)

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

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

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

xxhby3vn

xxhby3vn1#

在使用reflect.ValueOf之前,您可能需要检查它返回了什么。
在本例中,您将得到一个空值,因为reflect无法看到未导出的函数。hello以小写字母开头,因此不会导出。
另外,你在这里做了太多的指针,我怀疑你需要做reflect.ValueOf(c)。你在同时做和调试太多的事情。做一个简单的工作示例,然后从那里继续调试。
这对我很有效:https://play.golang.org/p/Yd-WDRzura

qfe3c7zg

qfe3c7zg2#

只需在代码中做两个更改。首先将reflect.ValueOf(&c)更改为reflect.ValueOf(c),然后将reflect.ValueOf(command)更改为reflect.ValueOf(*command)
这是代码workingcode

kt06eoxx

kt06eoxx3#

调用Kind()进行检查

type Header struct {
    Token string
}
    
type Request struct {
    Header 
}   

func requestedToken(request interface{}) string {
    requestValue := reflect.ValueOf(request)
    header := requestValue.FieldByName("Header12")
    if header.Kind() == 0 {
        return "" //Return here
    }
    token := header.FieldByName("Token")
    if token.Kind() == 0 {
        return ""
    }
    return token.String()
}
6tr1vspr

6tr1vspr4#

仅在此处发布(作为其他潜在解决问题)
在我的例子中,我有一个nil值,在.Elem()之后,结果是0值。
下面是我场景(当然是简化的)

var myTime *time.Time
if v := reflect.ValueOf(myTime); v.Kind() == reflect.Ptr {
    if v.IsNil() {
        fmt.Println("it is nil")
    } else {
        // do anything else
    }
}

没有“if”部分,我调用v.Elem().Interface(),其中Interface()在“零”值上调用。IsNil()现在阻止了这一点,在我这端一切都工作正常
希望有帮助:)
马克斯

66bbxpm5

66bbxpm55#

您需要将runCommandFromString更改为RunCommandFromString

相关问题