如何使用未导出的字段克隆结构?

abh*_*ink 5 struct clone go

如果我的类型定义为:

type T struct {
    S  string
    is []int
}
Run Code Online (Sandbox Code Playgroud)

那我怎么去克隆这种类型的对象呢?如果我做一个简单的任务:

p := T{"some string", []int{10, 20}}
q := p
Run Code Online (Sandbox Code Playgroud)

然后对[]int影响两个对象的任何更改.由于T.is未导出,因此即使使用反射提取也无法显式复制.

我正在提供Clone类型本身的包中的方法.但这对其他软件包中的类似类型没有帮助.还有另一种方法吗?

icz*_*cza 7

你不能.这是未导出字段的重点:只有声明包才能修改它们.

请注意,如果T在另一个包中声明了类型,则甚至无法编写:

p := somepackage.T{"some string", []int{10, 20}}
Run Code Online (Sandbox Code Playgroud)

因为这会隐式尝试设置未导出的T.is字段,从而导致编译时错误:

implicit assignment of unexported field 'is' in somepackage.T literal
Run Code Online (Sandbox Code Playgroud)

如果您拥有(或者您可以修改)包,最好是提供Clone()方法或功能,或提供SetIs()类型的方法T.如果第三方软件包没有提供此类功能,那么您无能为力.

请注意,使用包unsafe可以执行此类操作,但正如其名称所示:它不安全,您应该远离它.

另请注意,您可以创建未复制的Twhere的新值,is但将是其类型的零值(如果是[]int这样的话nil):

var r somepackage.T
s := somepackage.T{S: p.S}

fmt.Printf("%q\n", r)
fmt.Printf("%q\n", s)
Run Code Online (Sandbox Code Playgroud)

哪个会输出:

{"" []}
{"some string" []}
Run Code Online (Sandbox Code Playgroud)

但是,您无法为未导出的字段设置任何非零值T.is.