栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

有什么方法可以从另一个包访问结构的私有字段吗?

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

有什么方法可以从另一个包访问结构的私有字段吗?

一种方法来 读取 使用反映不导出成员

func read_foo(f *Foo) {    v := reflect.ValueOf(*f)    y := v.FieldByName("y")    fmt.Println(y.Interface())}

但是,尝试使用y.Set或通过其他方式设置反射字段将导致代码恐慌,您试图在软件包外部设置未导出的字段。

简而言之:未导出的字段出于某种原因应被取消导出,如果您需要更改它们,或者将需要更改的内容放在同一包中,或者公开/导出一些安全的更改方法。

也就是说,为了完全回答问题,您 可以 执行此操作

func change_foo(f *Foo) {    // Since structs are organized in memory order, we can advance the pointer    // by field size until we're at the desired member. For y, we advance by 8    // since it's the size of an int on a 64-bit machine and the int "x" is first    // in the representation of Foo.    //    // If you wanted to alter x, you wouldn't advance the pointer at all, and simply    // would need to convert ptrTof to the type (*int)    ptrTof := unsafe.Pointer(f)    ptrTof = unsafe.Pointer(uintptr(ptrTof) + uintptr(8)) // Or 4, if this is 32-bit    ptrToy := (**Foo)(ptrTof)    *ptrToy = nil // or *ptrToy = &Foo{} or whatever you want}

这是一个非常非常糟糕的主意。它不是可移植的,如果进行大小更改,它将失败;如果您重新排列Foo中的字段顺序,更改其类型或大小,或在现有字段之前添加新字段,此功能将极大地更改无需告知您即可随意处理乱码数据的新表示形式。我也认为这可能会破坏此块的垃圾回收。

请,如果您需要从程序包外部更改字段,请编写功能以从程序包内部进行更改或将其导出。

编辑:这是一种较为安全的方法:

func change_foo(f *Foo) {    // Note, simply doing reflect.ValueOf(*f) won't work, need to do this    pointerVal := reflect.ValueOf(f)    val := reflect.Indirect(pointerVal)    member := val.FieldByName("y")    ptrToY := unsafe.Pointer(member.UnsafeAddr())    realPtrToY := (**Foo)(ptrToY)    *realPtrToY = nil // or &Foo{} or whatever}

这样比较安全,因为它总是会找到正确的命名字段,但它仍然不友好,可能很慢,而且我不确定它是否与垃圾回收弄乱了。它也将无法警告你,如果你正在做一些奇怪的(你可以把这个代码
稍微 添加一些检查比较安全,但是我不会理会,这得到要点跨越不够好)。

Also keep in mind that FieldByName is susceptible to the package developer
changing the name of the variable. As a package developer, I can tell you that
I have absolutely no qualms about changing the names of things users should be
unaware of. You could use Field, but then you’re susceptible to the developer
changing the order of the fields with no warning, which is something I also
have no qualms about doing. Keep in mind that this combination of reflect and
unsafe is… unsafe, unlike normal name changes this won’t give you a compile
time error. Instead, the program will just suddenly panic or do something
weird and undefined because it got the wrong field, meaning even if YOU are
the package developer that did the name change, you still may not remember
everywhere you did this trick and spend a while tracking down why your tests
suddenly broke because the compiler doesn’t complain. Did I mention that this
is a bad idea?

Edit2:既然您提到了白盒测试,请注意,如果您在目录中命名文件,

<whatever>_test.go
除非您使用
gotest
,否则它将不会编译,因此,如果您要进行白盒测试,请在顶部声明
package<yourpackage>
,这将使您可以访问未导出的字段,如果您要做黑匣子测试,请使用
package <yourpackage>_test

但是,如果您需要同时对两个软件包进行白盒测试,我认为您可能会陷入困境,可能需要重新考虑您的设计。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/436163.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号