我正在尝试编写一个函数,该函数返回给调用者,从reflect.ValueOf(somefunc).Call(someargs)
的结果切片中获取错误结果。
我尝试了很多参考变种。调用,并键入断言。但似乎无法让编译器让我将reflect.Value
切片中的实际具体值放回普通的错误变量中。
以下是代码,使用os.Getwd
作为函数:
var somefunc interface{}
var errToCaller *error
somefunc = os.Getwd
ftype := reflect.TypeOf(somefunc)
errType := reflect.TypeOf(errToCaller).Elem()
resType := ftype.Out(1)
fmt.Println("resType.Implements(errType) = ",
resType.Implements(errType))
res := reflect.ValueOf(somefunc).Call([]reflect.Value{})
fmt.Printf("res[1] as %%v = %v\n", res[1])
fmt.Printf("res[1] as %%#v = %#v\n", res[1])
fmt.Printf("ValueOf(res[1]) as %%v = %v\n",
reflect.ValueOf(res[1]))
fmt.Printf("ValueOf(res[1]) as %%#v = %#v\n",
reflect.ValueOf(res[1]))
fmt.Printf("ValueOf(res[1]).Type() as %%#v = %#v\n",
reflect.ValueOf(res[1]).Type())
fmt.Printf("ValueOf(res[1]).Interface() as %%#v = %#v\n",
reflect.ValueOf(res[1]).Interface())
// *errToCaller = reflect.ValueOf(res[1])
// *errToCaller = reflect.ValueOf(res[1]).Interface()
// *errToCaller = reflect.ValueOf(res[1]).Interface().(error)
使用以下输出:
resType.Implements(errType) = true
res[1] as %v = <nil>
res[1] as %#v = error(nil)
ValueOf(res[1]) as %v = <error Value>
ValueOf(res[1]) as %#v = reflect.Value{typ:(*reflect.rtype)(0x4b9a60), ptr:(unsafe.Pointer)(0xc42000a3f0), flag:0x94}
ValueOf(res[1]).Type() as %#v = &reflect.rtype{size:0x18, ptrdata:0x10, hash:0x500c1abc, tflag:0x7, align:0x8, fieldAlign:0x8, kind:0x19, alg:(*reflect.typeAlg)(0x4a62d0), gcdata:(*uint8)(0x4daa41), str:21371, ptrToThis:184032}
ValueOf(res[1]).Interface() as %#v = error(nil)
我缩写了这个例子,删除了许多其他Printf语句,这些语句指示(至少对我来说)类型是相同的(即使我认为是reflect.Value
结构的相关字段)。 为什么,当所有各种打印语句似乎都告诉我结果是错误值时,我不能将它分配给我的本地变量吗?
取消注释上面代码示例中的第一个作业会导致编译器提出此抱怨:
./passerror.go:30: cannot use reflect.ValueOf(res[1]) (type reflect.Value) as type error in assignment:
reflect.Value does not implement error (missing Error method)
所以我认为我需要Interface()结果,但仍然没有运气(使用上面注释的第二个作业):
./passerror.go:31: cannot use reflect.ValueOf(res[1]).Interface() (type interface {}) as type error in assignment:
interface {} does not implement error (missing Error method)
最后,Interface()返回值的类型断言导致恐慌:
panic: interface conversion: reflect.Value is not error: missing method Error
无论我尝试过什么,我似乎无法摆脱可怕的reflect.Value
,这阻止了我对普通错误变量的分配。我试过Set()
也没有成功,但可能不正确。
我会永远感激这种洞察力和/或神奇的咒语。
修改
感谢https://stackoverflow.com/users/965900/mkopriva发表评论。代码需要一个真正的错误变量,而不仅仅是一个*错误,之后localerr = res[n].Interface().(error)
完美地运行。 (还使用伪造的参数将函数更改为os.Chdir以触发非零错误值)
答案 0 :(得分:1)
从Call返回的值是reflect.Value
的一个片段,所以不需要像在示例代码中那样将结果包装在另一个reflect.ValueOf
调用中:
reflect.ValueOf(res[1]) // not what you want
这样做会将值的基础类型从error
更改为reflect.Value
,这就是为什么随后调用.Interface().(error)
导致程序出现恐慌的原因。
因此,要修复代码,只需直接在结果上调用.Interface().(error)
,如下所示:
res[1].Interface().(error)
正如Cerise Limón已经指出的那样,当你做类型断言时,最好使用“逗号确定”的习惯来避免不必要的恐慌。
err, ok := res[1].Interface().(error)
if !ok {
// oops
}
或者,更简洁的替代方案:
if err, ok := res[1].Interface().(error); ok && err != nil {
// it's a non-nil error
}