在未导出的字段上调用导出的方法

时间:2019-12-05 13:19:43

标签: go methods reflection

我知道,有人问过类似的问题,但是我找不到这种情况的答案:

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所述),我有点希望也可以以某种方式访问​​该字段的公共方法。也许我只是在反映错误?

3 个答案:

答案 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的答案为您提供了不应该这样做的理由,这是使用reflectunsafe的一种方式:

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)

游乐场:https://play.golang.org/p/CmG9e4Bl9gg