我知道,有人问过类似的问题,但是我找不到这种情况的答案:
type ExportedStruct struct{ //comes from a dependency, so I can't change it
unexportedResource ExportedType
}
我想在Close()
上调用 exported 方法unexportedResource
。
我所做的是:
rs := reflect.ValueOf(myExportedStructPtr).Elem() //myExportedStructPtr is a pointer to an ExportedStruct object
resourceField := rs.FieldByName("unexportedResource")
closeMethod := resourceField.MethodByName("Close")
closeMethod.Call([]reflect.Value{reflect.ValueOf(context.Background())})
,结果为reflect.flag.mustBeExported using value obtained using unexported field
。
这很烦人,因为我想运行多个使用ExportedStruct
的测试,但是只要不使用基础资源,我就不能这样做。
由于我可以访问私有字段(如here所述),我有点希望也可以以某种方式访问该字段的公共方法。也许我只是在反映错误?
答案 0 :(得分:5)
未导出字段仅用于声明包。别惹他们。他们不适合你。
链接的答案只能使用软件包unsafe
来访问,该软件包并非日常使用。软件包unsafe
应随附“请勿触摸”手册。
如果您确实需要访问unexportedResource
,请将其导出。您可以在字段中添加方法,也可以在调用unexportedResource.Close()
的类型中添加方法。或在执行此操作的程序包中添加实用程序功能(同一程序包中的功能可以访问未导出的字段和标识符)。
答案 1 :(得分:1)
恐怕您想做的事通过反思是不可能的。
下面是reflect.Call的实现:
func (v Value) Call(in []Value) []Value {
v.mustBe(Func)
v.mustBeExported()
return v.call("Call", in)
}
如您所见,有一个显式检查(即mustBeExported()
)是否从导出的字段中获得了Value
。
通常存在不导出字段的原因。如果要操纵该字段,则必须使用ExportedStruct
结构实现的方法。
如果您可以修改定义ExportedStruct
的代码,则可以轻松地在其上实现包装器Close
的方法。例如:
type ExportedStruct struct{
unexportedResource ExportedType
}
func (e ExportedStruct) Close(){
e.unexportedResource.Close()
}
答案 2 :(得分:1)
@icza的答案为您提供了不应该这样做的理由,这是使用reflect
和unsafe
的一种方式:
var t pkg.T
v := reflect.ValueOf(&t).Elem()
f := v.FieldByName("t")
rf := reflect.NewAt(f.Type(), unsafe.Pointer(f.UnsafeAddr())).Elem()
rf.MethodByName("Print").Call(nil)