我有以下功能:
func addCatsToMap(m map[string][]CatHouse, meowId int, treats Set, dog *Dog) {
//if (complicated thing) add Cat to m
}
Run Code Online (Sandbox Code Playgroud)
其中Set,type的类型treats是具有以下定义的接口:
type Set interface {
Add(value string)
Contains(value string) (bool)
Length() (int)
RemoveDuplicates()
}
Run Code Online (Sandbox Code Playgroud)
题:
这是真的m,treats和dog是通过按引用,并且meowId有它的价值被复制?
我认为:
m 是传递参考,因为它是一张地图dog是一个结构.所以,我应该传递指针以避免复制数据jor*_*lli 38
接口类型只是一组方法.请注意,接口定义的成员不指定接收器类型是否为指针.这是因为值类型的方法集是其关联指针类型的方法集的子集.那是满口的.我的意思是,如果您有以下内容:
type Whatever struct {
Name string
}
Run Code Online (Sandbox Code Playgroud)
并定义以下两种方法:
func (w *Whatever) Foo() {
...
}
func (w Whatever) Bar() {
...
}
Run Code Online (Sandbox Code Playgroud)
然后类型Whatever只有方法Bar(),而类型*Whatever有方法Foo()和Bar().这意味着如果您有以下界面:
type Grits interface {
Foo()
Bar()
}
Run Code Online (Sandbox Code Playgroud)
然后*Whatever实现Grits但Whatever不实现,因为Whatever缺少方法Foo().将函数的输入定义为接口类型时,您不知道它是指针还是值类型.
以下示例说明了以两种方式获取接口类型的函数:
package main
import "fmt"
type Fruit struct {
Name string
}
func (f Fruit) Rename(name string) {
f.Name = name
}
type Candy struct {
Name string
}
func (c *Candy) Rename(name string) {
c.Name = name
}
type Renamable interface {
Rename(string)
}
func Rename(v Renamable, name string) {
v.Rename(name)
// at this point, we don't know if v is a pointer type or not.
}
func main() {
c := Candy{Name: "Snickers"}
f := Fruit{Name: "Apple"}
fmt.Println(f)
fmt.Println(c)
Rename(f, "Zemo Fruit")
Rename(&c, "Zemo Bar")
fmt.Println(f)
fmt.Println(c)
}
Run Code Online (Sandbox Code Playgroud)
你可以调用Raname(&f, "Jorelli Fruit"),但不能Rename(c, "Jorelli Bar"),因为这两个Fruit和*Fruit实施Renamable,而*Candy工具Renable和Candy没有.
http://play.golang.org/p/Fb-L8Bvuwj
通过引用传递是一种语言的东西,Go中的任何内容都不是"通过引用传递".通过引用传递意味着赋值操作符可以在单独使用时更改原始值.但是,有一些引用类型,例如指向某处的地图和指针.除非使用其他运算符(如映射索引和*运算符),否则在它们上使用赋值运算符将不会修改原始运算符.
你的地图m是一个引用类型,因此就像一个指针.除替换地图外,对地图的任何更改都将修改原始地图.
m["whatever"] = 2 // Modifies the original map
m = anothermap // Does not modify the original map
Run Code Online (Sandbox Code Playgroud)
如果存在真正的"按引用传递",则第二个示例将修改原始地图.
传递指针,就像您一样,dog允许您修改原始.如果您调用任何指针方法或使用*运算符,原始将更改.在您的示例中,可能不需要指针.如果Dog很小,可能更容易传递副本.由程序员决定何时使用指针是一个好时机.
Set未通过引用传递.接口不是引用.虽然在6g编译器内部接口使用指针是正确的,但接口本身并不像一个接口.传递接口,无论它包含的对象的大小,都与使用6g编译器传递指针一样便宜.但是,无法使用指针和贴图修改接口的原始值.
虽然您无法修改传递的原始接口,但该接口可以包含指针类型.在这种情况下,它将像狗指针一样,调用某些方法可以修改原始.对于您的特定Set接口,我猜它包含基于方法名称的指针类型.因此,当您致电时set.Add(whatever),它将更改原始内部数据.