有没有办法使用Reflect访问go 1.8中未导出的字段? 这似乎不再起作用:https://stackoverflow.com/a/17982725/555493
请注意,reflect.DeepEqual
工作得很好(也就是说,它可以访问未导出的字段),但我无法对该功能进行正面或反面操作。这是一个可以显示实际效果的游戏区:https://play.golang.org/p/vyEvay6eVG。 src代码在
import (
"fmt"
"reflect"
)
type Foo struct {
private string
}
func main() {
x := Foo{"hello"}
y := Foo{"goodbye"}
z := Foo{"hello"}
fmt.Println(reflect.DeepEqual(x,y)) //false
fmt.Println(reflect.DeepEqual(x,z)) //true
}
答案 0 :(得分:12)
如果结构是可寻址的,您可以使用unsafe.Pointer
来访问该字段(读取或写),如下所示:
rs := reflect.ValueOf(&MyStruct).Elem()
rf := rs.Field(n)
// rf can't be read or set.
rf = reflect.NewAt(rf.Type(), unsafe.Pointer(rf.UnsafeAddr())).Elem()
// Now rf can be read and set.
See full example on the playground.
unsafe.Pointer
的使用是有效的"根据{{1}}包的文档,以及unsafe
的干净利落。
如果结构不可寻址,这个技巧不会起作用,但你可以创建一个这样的可寻址副本:
go vet
答案 1 :(得分:3)
基于cpcallen的工作:
import (
"reflect"
"unsafe"
)
func GetUnexportedField(field reflect.Value) interface{} {
return reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).Elem().Interface()
}
func SetUnexportedField(field reflect.Value, value interface{}) {
reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).
Elem().
Set(reflect.ValueOf(value))
}
reflect.NewAt
乍一看可能会令人困惑。它使用reflect.Value
作为指针,返回代表指定field.Type()
值的指针的unsafe.Pointer(field.UnsafeAddr())
。在这种情况下,reflect.NewAt
与reflect.New
不同,type Foo struct {
unexportedField string
}
GetUnexportedField(reflect.ValueOf(&Foo{}).Elem().FieldByName("unexportedField"))
将返回指向新初始化值的指针。
示例:
1
答案 2 :(得分:2)
reflect.DeepEqual()
可以执行此操作,因为它可以访问reflect
包的未导出功能,在这种情况下,即valueInterface()
函数,它接受safe
参数,如果safe=true
,则拒绝通过Value.Interface()
方法访问未导出的字段值。 reflect.DeepEqual()
将(可能)称之为传递safe=false
。
您仍然可以执行此操作,但不能将Value.Interface()
用于未导出的字段。相反,您必须使用特定于类型的方法,例如string
为Value.Interface()
,浮点数为Value.String()
,int为Value.Float()
等。这些将返回值的副本(这足以检查它),但不允许你修改字段的值(如果type Foo struct {
s string
i int
j interface{}
}
func main() {
x := Foo{"hello", 2, 3.0}
v := reflect.ValueOf(x)
s := v.FieldByName("s")
fmt.Printf("%T %v\n", s.String(), s.String())
i := v.FieldByName("i")
fmt.Printf("%T %v\n", i.Int(), i.Int())
j := v.FieldByName("j").Elem()
fmt.Printf("%T %v\n", j.Float(), j.Float())
}
可行,那么可能是"部分"可能是字段类型指针类型)。
如果字段碰巧是接口类型,您可以使用Value.Int()
来获取接口值包含/包装的值。
演示:
string hello
int64 2
float64 3
输出(在Value.Elem()
上尝试):
RestTemplate rest = new RestTemplate();
String responseEntity;
String uri = "http://...";
responseEntity = rest.postForObject(uri, null, String.class);
System.out.println(responseEntity);