我有一个简单的结构,只有一个方法:
type Person struct {
name string
}
func (p Person) SetName(name string) {
p.name = name
}
以下输出:
dave := Person{}
dave.SetName("Dave")
fmt.Println(dave.name)
将为空,因为方法接收器接受一个值(或者更准确地创建您传递的值的副本),因此它不会修改您的基础值。
如果我将方法更改为:
func (p *Person) SetName(name string) {
p.name = name
}
输出将是" Dave"。
现在我不明白的是我不应该在指针上调用方法吗? 因此,当初始化我的对象时,我应该这样做:
dave := &Person{}
而不是:
dave := Person{}
同样使用go反射包我试图找出以下值:
&Person
并发现它是*人,这很好。当我打印该值虽然我没有获得内存位置相比,当我打印指向int的指针的值时:
a := 4
fmt.Println(&a)
我一直在阅读文档,提出问题,但我学的越多,我就越想知道我是否遗漏了一些简单的东西,因为很多人都认为这一切都让人困惑。
答案 0 :(得分:6)
您在指针接收器上调用方法并保留指向值的指针时会感到困惑。也就是说,在指针接收器上定义的调用SetName
之间没有固有的连接,需要存储指向存储类型为Person
的存储器的存储器{直接{1}}。
当你有声明时
Person
然后致电
var pers Person
编译器获取所占用的内存块的地址
变量pers.SetName("foo")
- 就像你通过申请手工做的那样
将pers
运算符设为&
,并将该地址传递给pers
函数,所以调用最终完成像
SetName
或者,换句话说,(&pers).SetName("foo")
的接收器将是
SetName
- 即&pers
的地址。
现在没有什么可以阻止你获取pers
的地址
并将其存储在其他地方:
pers
(你通常不会写这种Java风格的口吃代码,但是
我这样做是为了更清晰),现在你可以打电话了
var ptr *Person = &pers
值上的SetName
:
ptr
现在编译器将直接使用存储在变量ptr.SetName("bar")
中的值
将其作为方法的接收者传递。
这个"拼图的最后一点"是你用的时候
Go-applied地址获取操作符ptr
提供的特殊语法
直接到文字,编译器做这样的事情:
&
...并使var __pers Person = Person{
// The contents of your literal
}
var dave = &__pers
变量无法按名称访问(因为它很自然
没有名字。)
正如您所看到的,这与获取指针没有什么不同
用手记住__pers
值的记忆。
您可能需要咨询this FAQ entry以获得更多理解
方法如何设置类型Person
和T
相关联,以及后者为什么
总是包括前者,但反之亦然。
另请阅读this。
更新:解释*T
格式和输出方式的差异
类型fmt.Println
和*int
的值。
*Person
值的内存位置的地址。int
。此行为符合记录:&{}
和fmt.Print
对它们的参数使用所谓的默认格式规则
传递,这些规则取决于参数的类型。
让我们先查看fmt.Println
上的文档
(运行fmt.Println
):
go doc fmt.Println
func Println(a ...interface{}) (n int, err error)
格式使用其操作数的默认格式 并写入标准输出。 始终在操作数之间添加空格,并附加换行符。 它返回写入的字节数和遇到的任何写入错误。
(强调我的。)
现在让我们转到Println
包本身的文档
(运行fmt
):
< ...>
打印
动词:
一般:
go doc fmt
默认格式的值打印结构时,加号标记(
%v
)会添加字段名称。< ...>
%+v
的默认格式为:%v
对于复合对象,使用这些规则打印元素, 递归地,这样布局:
bool: %t int, int8 etc.: %d uint, uint8 etc.: %d, %#x if printed with %#v float32, complex64, etc: %g string: %s chan: %p pointer: %p
struct: {field0 field1 ...}
array, slice: [elem0 elem1 ...]
maps: map[key1:value1 key2:value2]
pointer to above: &{}, &[], &map[]
是指向结构类型的指针,因此它呈现为
*Person
其中&{name}
是name字段的内容;比方说,如果它被分配了
字符串" Dave",输出为name
。