提问人:z11i 提问时间:2/20/2020 最后编辑:iczaz11i 更新时间:2/20/2020 访问量:4231
切片与类型别名作为方法接收器
Slice vs type alias as the method receiver
问:
我有一个带有方法的结构体:Foo
print
type Foo struct {
Bar string
}
func (f Foo) print() {
fmt.Println(f.Bar)
}
如果我想打印一个切片,规范的方法可能是编写一个循环,并有一个函数来封装它:Foo
for
func printFoos(fs []Foo) {
for _, f := range fs {
f.print()
}
}
printFoos([]Foo{})
来自OOP背景,我发现这种方法有点不吸引人。
我想做的是与:printFoos
[]Foo
// Invalid Go code
func (fs []Foo) print() {
for _, f := range fs {
f.print()
}
}
上述方法不起作用,因为在 Go 中,未命名的类型不能用作方法接收器,正如此 Google Group 线程中所讨论的那样。
为了规避它,可以写成:
type Foos []Foo
func (fs Foos) print() {
for _, f := range fs {
f.print()
}
}
要使用它,我必须显式声明类型为 ,所以我仍然不能使用Foos
print
[]Foo
fs := []Foo{}
fs.print() // error
var fss Foos = fs
fss.print()
我感到困惑的是,在上面的代码中,它们显然属于同一类型,因为我可以毫无错误地分配给它们。但是,我们不能简单地使用并让 Go 聪明地进行转换。fss
fs
fs
fss
fs.print()
为什么会这样?
完整的代码可以在 playground 上找到。
答:
11赞
icza
2/20/2020
#1
我感到困惑的是,在上面的代码中,它们显然属于同一类型,因为我可以毫无错误地分配给它们。
fss
fs
fs
fss
你得出了错误的结论。具有相同的类型不是可分配性的必要条件。
fss
has type 和 has type ,一种未命名的切片类型。确实,它们具有相同的基础类型,这就是为什么您可以分配给 ,在此可分配性规则中介绍:Foos
fs
[]Foo
fs
fss
如果满足以下条件之一,则值可分配给类型为(“可分配给”)的变量:
x
T
x
T
方法绑定到具体类型。因此,该方法不适用于其他类型的值,包括 。Foos.print()
[]Foo
但是你不需要创建一个变量来调用该方法,你可以简单地使用类型转换:
Foos(fs).print()
此转换不会更改内存布局,只会更改类型,因此安全高效。我们仅使用它来访问具有相同基础类型的类型的方法。
评论
0赞
Shuzheng
11/9/2021
V
或 T
中的至少一个不是定义的类型是什么意思?不是两种类型都定义了吗?IOW,也是一个定义的类型。type Foos Foo[]
0赞
icza
11/9/2021
@Shuzheng 是定义的类型,但 的参数,这里的 type 是 ,它不是定义的类型。这意味着 的类型可以赋值给 类型的变量,因此可以作为 的参数传递,因为可赋值性规则适用(“V
或 T
中的至少一个不是定义类型” – 不是定义类型)。Foos
printFoos(fs []Foo)
fs
[]Foo
Foos
[]Foo
fs
[]Foo
评论
print
Foos
[]Foo