我有一个Foo
带有方法的结构print
:
type Foo struct {
Bar string
}
func (f Foo) print() {
fmt.Println(f.Bar)
}
Run Code Online (Sandbox Code Playgroud)
如果我想打印一个切片Foo
,规范的方法可能是编写一个for
循环,并有一个函数来封装它:
func printFoos(fs []Foo) {
for _, f := range fs {
f.print()
}
}
printFoos([]Foo{})
Run Code Online (Sandbox Code Playgroud)
来自 OOP 背景,我发现这种方法有点不吸引人。
我想做的是printFoos
与[]Foo
:
// Invalid Go code
func (fs []Foo) print() {
for _, f := range fs {
f.print()
}
}
Run Code Online (Sandbox Code Playgroud)
以上不起作用,因为在 Go 中,未命名类型不能用作方法接收器,如Google Group thread 中所述。
为了规避它,可以写:
type Foos []Foo
func (fs Foos) print() {
for _, f := range fs {
f.print()
}
}
Run Code Online (Sandbox Code Playgroud)
要使用它,我必须显式声明的类型Foos
,所以我仍然无法使用print
上[]Foo
fs := []Foo{}
fs.print() // error
var fss Foos = fs
fss.print()
Run Code Online (Sandbox Code Playgroud)
我感到困惑的是,在上面的代码,fss
而fs
显然是同类型的,因为我可以分配fs
到fss
没有错误。但是,我们不能简单地使用fs.print()
并让 Go 智能地进行转换。
为什么会这样?
完整代码可以在playground上找到。
我感到困惑的是,在上面的代码,
fss
而fs
显然是同类型的,因为我可以分配fs
到fss
没有错误。
你跳到错误的结论。具有相同的类型并不是可分配性的必要条件。
fss
有 typeFoos
和fs
type []Foo
,一种未命名的切片类型。确实,它们具有相同的基础类型,这就是为什么您可以分配fs
给fss
,包含在此可分配性规则中:
的值
x
是分配给可变型的T
(“x
是分配给T
”),如果满足下列条件中的一个适用:
方法绑定到具体类型。因此,该Foos.print()
方法不适用于不同类型的值,包括[]Foo
.
但是您不需要创建一个变量来调用该方法,您可以简单地使用类型转换:
Foos(fs).print()
Run Code Online (Sandbox Code Playgroud)
这种转换不改变内存布局,只改变类型,所以安全高效。我们仅使用它来访问具有相同基础类型的类型的方法。