我在一个包中有一个 struct ,其中包含私有字段:

package foo

type Foo struct {
    x int
    y *Foo
}

另一个软件包(例如,白盒测试软件包)需要访问它们:

package bar

import "../foo"

func change_foo(f *Foo) {
    f.y = nil
}

有没有一种方法可以声明bar是一种"朋友"包,或者其他任何方法可以从bar访问foo.Foo的私有成员,但仍然保持所有其他包的私有成员(可能是unsafe中的某个)?

推荐答案

is种方法可以使用反射(在Go<;1.7中)处理read个未导出的成员

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

但是,try 使用y.Set,或以其他方式使用reflect设置字段将导致代码panic ,因为您试图在包外设置未报告的字段.

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

也就是说,为了完全回答这个问题,你们can人这样做(并且在go>;=1.7中必须这样做)

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

}

这是个非常非常糟糕的主意.它是不可移植的,如果int的大小发生变化,它就会失败,如果你在Foo中重新排列字段的顺序,改变它们的类型或大小,或者在已有字段之前添加新字段,这个函数会在不告诉你的情况下愉快地将新的表示形式更改为随机乱码数据.我还认为这可能会 destruct 这个街区的垃圾收集.

请注意,如果您需要从包外部更改字段,可以编写功能从包内更改它,也可以将其导出.

编辑2:由于您提到了白盒测试,请注意,如果您将目录<whatever>_test.go中的一个文件命名为<whatever>_test.go,除非您使用go test,否则它不会编译,所以如果您想要进行白盒测试,请在顶部声明package <yourpackage>,它将允许您访问未导出的字段,如果您想要进行黑盒测试,那么您可以使用package <yourpackage>_test.

但是,如果您需要同时对两个软件包进行白盒测试,我认为您可能会被卡住,需要重新考虑您的设计.

Go相关问答推荐

如何在gocql中设置gocqlSYS标志?

Go Colly-访问for循环中的URL

需要类型[]*structpb.Value(GCP Golang客户端库;aiPlatform)

Go源在Goland(IDEA)中以灰色显示.什么意思?我怎么才能让它恢复正常?

格式化 Azure SDK 的 golang 时间

有没有办法让sqlc生成可以使用pgxpool的代码

使用 httptest 对 http 请求进行单元测试重试

gopacket:IP-in-IP 数据包上的解码层

在两个单独的速率受限端点之间同步请求

如何在 gocql 中设置最大池大小?

如何使用泛型将接口转换为指定类型

整理时转换值

访问传递给可变参数函数的通用 struct 的特定字段

GRPC 元数据未在 Go 中更新

使用 package`regexp` 查找 Golang 中的所有 mactch 子字符串,但得到意外结果

在 GORM 中,如何在特定时区配置 autoCreateTime 和 autoUpdateTime?

如何使用golang操作很长的字符串以避免内存不足

将 Simple Go Web 应用程序部署到 Elastic Beanstalk

Go模板中的浮点除法

在 go (1.18) 的泛型上实现多态的最佳方法是什么?