Pointers 指针上的golang指针作为函数参数
我有以下功能:Pointers 指针上的golang指针作为函数参数,pointers,go,Pointers,Go,我有以下功能: 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)
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()
}
问题:
m
、treats
和dog
是通过引用传递的,并且meowId
复制了它的值,这是真的吗
我假设:
是通过引用传递的,因为它是一个映射m
是一个结构。因此,我应该传递指针以避免复制数据dog
*
操作符,否则对其使用赋值操作符不会修改原始值
您的mapm
是一种引用类型,因此类似于指针,这是正确的。除替换地图外,对地图的任何更改都将修改原始地图
m["whatever"] = 2 // Modifies the original map
m = anothermap // Does not modify the original map
如果存在真实的“通过引用传递”,则第二个示例将修改原始地图
传递一个指针,就像使用dog
一样,允许您修改原始文件。如果调用任何指针方法或使用*
运算符,则原始值将更改。在您的示例中,可能不需要指针。如果Dog
很小,只需传递一份副本可能会更容易。由程序员决定何时是使用指针的好时机
Set
不是通过引用传递的接口不是引用。虽然在6g编译器内部,接口确实使用指针,但接口本身的行为与指针不同。传递一个接口,不管它包含的对象大小,都和使用6g编译器传递指针一样便宜。但是,无法像使用指针和映射那样修改接口的原始值
虽然不能修改传递的原始接口,但该接口可以包含指针类型。在这种情况下,它的行为就像狗指针一样,在这里调用某些方法可以修改原始的。对于特定的
Set
接口,我猜它包含基于方法名称的指针类型。因此,当您调用set.Add(无论什么)
时,它将更改原始的内部数据。接口类型只是一组方法。请注意,接口定义的成员不指定接收器类型是否为指针。这是因为值类型的方法集是其关联指针类型的方法集的子集。那是一口。我的意思是,如果你有以下几点:
m["whatever"] = 2 // Modifies the original map
m = anothermap // Does not modify the original map
type Whatever struct {
Name string
}
您可以定义以下两种方法:
func (w *Whatever) Foo() {
...
}
func (w Whatever) Bar() {
...
}
然后类型Whatever
只有方法Bar()
,而类型*Whatever
有方法Foo()
和Bar()
。这意味着如果您具有以下界面:
type Grits interface {
Foo()
Bar()
}
然后*which
实现砂砾但是which
没有,因为which
缺少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)
}
您可以调用Raname(&f,“Jorelli果”)
,但不能重命名(c,“Jorelli条”)
,因为果和*果都实现可重命名,而*糖果实现可重命名,而糖果不实现
在函数调用中,函数值和参数在
通常的顺序。在对它们求值之后,调用的参数
按值传递给函数,被调用函数开始
执行。函数的返回参数按值传递
当函数返回时返回到调用函数
与C系列中的所有语言一样,
Go中的所有内容都是按值传递的。也就是说,函数总是得到一个
正在传递的对象的副本,好像有一个任务
将值指定给参数的语句。比如传球
函数的int值生成int的副本,并传递
指针值复制指针,但不复制指针所指向的数据
到(有关这如何影响方法的讨论,请参见下一节。)
接收器。)
映射和切片值的行为类似于指针:它们是
包含指向基础映射或切片数据的指针。复制地图或
切片值不会复制它指向的数据。复制接口
值生成存储在接口值中的对象的副本。如果
接口值保存一个结构,复制接口值会生成一个
结构的副本。如果接口值包含指针,则复制
接口值生成指针的副本,但同样不是指针的副本
它指向的数据