我有以下功能:
func addCatsToMap(m map[string][]CatHouse, meowId int, treats Set, dog *Dog) {
//if (complicated thing) add Cat to m
}
其中 Set
, treats
的类型是具有以下定义的接口:
type Set interface {
Add(value string)
Contains(value string) (bool)
Length() (int)
RemoveDuplicates()
}
Question:
m
, treats
和 dog
是否通过引用传递, meowId
是否复制了它的值?
我认为:
-
m
是传递引用,因为它是一张 Map -
dog
是一个结构 . 所以,我应该传递指针以避免复制数据
3 回答
接口类型只是一组方法 . 请注意,接口定义的成员不指定接收器类型是否为指针 . 这是因为值类型的方法集是其关联指针类型的方法集的子集 . 那是满口的 . 我的意思是,如果您有以下内容:
并定义以下两种方法:
然后类型
Whatever
只有方法Bar()
,而类型*Whatever
有方法Foo()
和Bar()
. 这意味着如果您有以下界面:然后
*Whatever
实现Grits
但Whatever
没有,因为Whatever
缺少方法Foo()
. 将函数的输入定义为接口类型时,您不知道它是指针还是值类型 .以下示例说明了以两种方式获取接口类型的函数:
你可以调用
Raname(&f, "Jorelli Fruit")
而不是Rename(c, "Jorelli Bar")
,因为Fruit
和*Fruit
都实现了Renamable
,而*Candy
实现了Renable
而Candy
没有 .http://play.golang.org/p/Fb-L8Bvuwj
通过引用传递是一种语言,Go中的任何内容都不是"pass by reference" . 通过引用传递意味着赋值操作符可以在单独使用时更改原始值 . 但是,有一些引用类型,例如指向某处的 Map 和指针 . 除非使用其他运算符(如map索引和
*
运算符),否则对它们使用赋值运算符将不会修改原始运算符 .你的 Map
m
是一个引用类型是正确的,因此就像一个指针 . 除替换 Map 外,对 Map 的任何更改都将修改原始 Map .如果存在真正的“按引用传递”,则第二个示例将修改原始 Map .
像
dog
一样传递指针允许您修改原始指针 . 如果您调用任何指针方法或使用*
运算符,原始将更改 . 在您的示例中,可能不需要指针 . 如果Dog
很小,则传递副本可能更容易 . 由程序员决定何时使用指针是一个好时机 .Set
未通过引用传递 . Interfaces are not references. 虽然在6g编译器内部确实是接口使用指针,但接口本身并不像一个接口 . 传递接口,无论它包含的对象的大小,都与使用6g编译器传递指针一样便宜 . 但是,无法使用指针和贴图修改接口的原始值 .虽然您无法修改传递的原始接口,但该接口可以包含指针类型 . 在这种情况下,它将像狗指针一样,调用某些方法可以修改原始 . 对于您的特定
Set
接口,我猜它包含基于方法名称的指针类型 . 因此,当您调用set.Add(whatever)
时,它将更改原始内部数据 .