如果结构浅拷贝,如何强制编译器错误?
我维护一个库,其中导出的结构具有不应浅拷贝的字段。例如:
type Example struct {
Val int
Nums []int
}
作为Nums切片类型的字段,Foo实例的浅拷贝复制切片头并允许错误:
foo := Example{Val: 1, Nums: []int{100}}
bar := Example
bar.Nums[0] = 200
fmt.Println(foo.Nums) // [200]
我想防止代码导入库以浅拷贝结构。可能的解决方案:
- 返回一个指针的构造函数,但无论如何都不能阻止客户端取消引用和浅拷贝:
pfoo := lib.NewFoo() // returns type `*Foo`
foo := *pfoo // now variable foo is type `Foo`
foo2 := foo // I don't want this
- 向库中添加丰富的文档以阻止浅拷贝。我也可以声明在我的库中的所有方法,其使用
Foos到需要指针类型,使事情变得安全在我身边,但同样,进口商代码可能会改写函数使用Foo的值。 - 添加一个
Clone()方法到Foo,但这属于“文档”问题:人们可能不会阅读它。 - 添加自定义检查,
go vet但这不会导致编译器错误。 - 重写库以避免暴露的不可复制字段
- 忍受出现错误的可能性
但是,还有另一种方法可以强制编译器在结构浅拷贝上抛出错误吗?
回答
问题运行时:添加 NoCopy 文档结构类型?解决这个问题。对该问题
的评论推荐了此解决方案:
请注意,绝对必须选择加入 vet 检查的代码已经可以这样做了。一个包可以定义:
type noCopy struct{} func (*noCopy) Lock() {}然后将 noCopy noCopy 放入任何必须由 vet 标记的结构中。
还需要 Unlock 方法来触发警告。这是示例的完整解决方案:
type noCopy struct{}
func (*noCopy) Lock() {}
func (*noCopy) Unlock() {}
type Example struct {
noCopy noCopy
Val int
Nums []int
}
通过此更改,该go vet命令会打印assignment copies lock value to y:Example contains noCopy以下代码的警告:
var x Example
y := x
在操场上运行示例。
记录不应复制该值的要求。Clone()如果应用程序需要深拷贝,请提供一种方法。
该方法不会增加 的大小,Example因为 a 的大小 struct{}为零。
标准库sync.WaitGroup类型使用 这种方法。