U A*_*los 9 reflection go private-members
有没有办法使用Reflect访问go 1.8中未导出的字段?这似乎不再起作用:https://stackoverflow.com/a/17982725/555493
请注意,reflect.DeepEqual工作正常(也就是说,它可以访问未导出的字段),但我无法做出该功能的正面或反面.这是一个go playarea,它显示了它的实际效果: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
}
Run Code Online (Sandbox Code Playgroud)
cpc*_*len 14
如果结构是可寻址的,您可以使用它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.
Run Code Online (Sandbox Code Playgroud)
unsafe.Pointer根据unsafe包的文档,这种使用是"有效的" ,go vet干净利落.
如果结构不可寻址,这个技巧将不起作用,但你可以创建一个这样的可寻址副本:
rs = reflect.ValueOf(MyStruct)
rs2 := reflect.New(rs.Type()).Elem()
rs2.Set(rs)
rf = rs2.Field(0)
rf = reflect.NewAt(rf.Type(), unsafe.Pointer(rf.UnsafeAddr())).Elem()
// Now rf can be read. Setting will succeed but only affects the temporary copy.
Run Code Online (Sandbox Code Playgroud)
基于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))
}
Run Code Online (Sandbox Code Playgroud)
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"))
Run Code Online (Sandbox Code Playgroud)
https://play.golang.org/p/IgjlQPYdKFR
reflect.DeepEqual()可以这样做,因为它可以访问reflect包的未导出功能,在这种情况下,即valueInterface()函数,它接受一个safe参数,拒绝通过Value.Interface()方法 if访问未导出的字段值safe=true。reflect.DeepEqual()将(可能)称为传递safe=false.
您仍然可以这样做,但不能Value.Interface()用于未导出的字段。相反,您必须使用特定于类型的方法,例如Value.String()for string、Value.Float()浮点数、Value.Int()整数等。这些将返回值的副本(足以检查它),但不允许您修改字段的值(如果Value.Interface()可以工作并且字段类型是指针类型,这可能是“部分”可能的)。
如果字段恰好是接口类型,则可以使用Value.Elem()来获取接口值包含/包装的值。
展示:
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())
}
Run Code Online (Sandbox Code Playgroud)
输出(在Go Playground上试试):
string hello
int64 2
float64 3
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7547 次 |
| 最近记录: |