英文:
panic: reflect: call of reflect.Value.Call on zero Value
问题
我正在尝试使用反射来根据用户输入进行动态函数调用。我正在收集用户输入,代码如下:
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
但实际上我得到了一个 panic,错误信息如下:
> 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
我该如何修复这个问题?还有,发生了什么?
英文:
I'm trying to use reflection in order to make a dynamic function call based on user input. I'm collecting user input like such:
func main() {
for {
reader := bufio.NewReader(os.Stdin)
fmt.Print("> ")
command, _ := reader.ReadString('\n')
runCommandFromString(command)
}
}
This is how the command is parsed out
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)
}
The commands.go file looks like this
type Command struct {
Name string
Args []string
}
type Commander struct {}
func (c Commander) Hello(cmd Command) {
fmt.Println("Meow", cmd.Args)
}
When I run the program, I get a prompt and I run a command called "Hello" with a param called "world". I would expect "Meow [World]" or something like that to appear. Like this:
> Hello world
Meow world
Instead what I get is a panic that looks like this:
> 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
How can I fix this? Also, what is happening?
答案1
得分: 9
在使用reflect.ValueOf
之前,你可能需要检查它返回的内容。
在这种情况下,你得到了一个空值,因为反射无法识别未导出的函数。hello
以小写字母开头,因此未导出。
此外,你在这里创建了太多的指针,我怀疑你需要执行reflect.ValueOf(c)
。你同时进行了太多的调试工作。先创建一个简单的可工作示例,然后从那里继续进行调试。
这个示例对我有效:https://play.golang.org/p/Yd-WDRzura
英文:
You might want to check what reflect.ValueOf
returns before using it.
In this case you're getting a nil value because reflect can not see functions that aren't exported. hello
starts with a lower case letter and therefore isn't exported.
Also, you're making too many pointers here, I suspect that you need to do reflect.ValueOf(c)
. You're doing and debugging too many things at the same time. Make a simple working example and continue debugging from there.
This works for me: https://play.golang.org/p/Yd-WDRzura
答案2
得分: 8
只需在你的代码中做两个更改。
第一个更改将reflect.ValueOf(&c)
更改为reflect.ValueOf(c)
第二个更改将reflect.ValueOf(command)
更改为reflect.ValueOf(*command)
这是代码workingcode
英文:
Just do two changes in your code.
First change reflect.ValueOf(&c)
to reflect.ValueOf(c)
Secondly change reflect.ValueOf(command)
to reflect.ValueOf(*command)
This is the code workingcode
答案3
得分: 2
调用Kind()函数来检查
type Header struct {
Token string
}
type Request struct {
Header
}
func requestedToken(request interface{}) string {
requestValue := reflect.ValueOf(request)
header := requestValue.FieldByName("Header")
if header.Kind() == reflect.Invalid {
return "" // 在这里返回
}
token := header.FieldByName("Token")
if token.Kind() == reflect.Invalid {
return ""
}
return token.String()
}
英文:
Call Kind() to check
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()
}
答案4
得分: 0
只是在这里发布(作为一个额外的潜在解决问题)
> 在我的情况下,我有一个空值,经过 .Elem() 后,结果为 0 值。
这是我的场景(当然是简化的)
var myTime *time.Time
if v := reflect.ValueOf(myTime); v.Kind() == reflect.Ptr {
if v.IsNil() {
fmt.Println("它是空值")
} else {
// 做其他事情
}
}
没有 "if" 部分,我调用了 v.Elem().Interface()
,其中 Interface() 是在 "零" 值上调用的。现在的 IsNil() 防止了这种情况,一切在我的端上都正常工作
希望对你有所帮助
Max
英文:
Just posting here (as an additional potential solving issue)
> In my case, I had a nil value which was, after a .Elem(), resulting as a 0 value..
here is my scenario (simplified of course)
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
}
}
Without the "if" part, I was calling v.Elem().Interface()
where Interface() was called on "zero" value. The IsNil() now prevents this and everything is working fine on my end
Hope it helps
Max
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论