我对指针方法接收器和非指针方法接收器的理解是,第一个可以在方法中修改,第二个不能。
所以,下面的工作完全符合我的预期。
type student struct {
name string
age int
}
func (s *student) update() {
s.name = "unknown"
s.age = 0
}
func main() {
s := student{"hongseok", 13}
fmt.Println(s)
s.update()
fmt.Println(s)
}
字符串
它打印hongseok/13和unknown/0。
但是,我想把update方法中的所有s都替换为reassigning。所以,我把update方法修改如下。
func (s *student) update() {
s = &student{"unknown", 0}
}
型
它不会改变main方法中的s,并打印双hongseok/13。
func (s *student) update() {
*s = student{"unknown", 0}
}
型
以上的改变解决了这个问题。
我觉得语义上没什么区别。我错过了什么?
3条答案
按热度按时间7dl7o3gd1#
在第一个例子中:
字符串
您正在为
s
分配一个全新的“指针值”,而新的*s
指向新的student
值。变量s
的作用域仅限于方法体,因此在此返回后没有副作用。在第二示例中
型
您正在解引用
s
,并将*s
的值更改为指向新的student
值,或者换句话说,您正在将新的student
值放置在s
指向的地址处。mwkjh3gx2#
在本例中,您将存储在
s
中的地址更改为不同的值;字符串
虽然使用指针被认为是“通过引用传递”,但引用本身是一个像任何其他值一样被推送到调用堆栈上的值。当您返回main时,
s
的值是该范围内的任何值。因此,为了给予更具体的内容,您使用s = 1
调用main(为简单起见,调用地址1和2),在方法中,您分配位于地址2的新student
并设置s = 2
,当你返回时,s
的版本从堆栈中弹出,main中的s
指向1
,它没有改变。在后一个例子中;
型
你正在解引用
s
并将一个新的对象分配到该位置,重新分配现有的内存。当你返回时,main中的指针仍然指向同一个位置,但在内存中的该位置有不同的数据。因此在这个例子中,你正在写入一个新的student
示例,以地址1
,所以当你返回时,你会在调用范围中看到新的值。dxpyg8gm3#
我想,你的主要问题是你的问题中出现的两个概念你都不太理解。
让我们从指针开始。当你不使用指针时,赋值意味着创建一个前一个值的简单副本。新值与前一个值没有任何关系。这意味着如果你改变旧值或新值,它不会影响第二个值。这对于基本类型(如int,bool,string)和结构是正常的。
字符串
现在是指针-它指向内存中的某个空间。为了简单起见,我们创建两个指针,它们都指向同一个地方。
型
不要混淆-指针也可以指向命名值。
型
现在回到方法,接收器是/不是指针。如果方法的接收器是指针,这意味着你可以改变它的值--就像我几行前做的一样。
如果方法接收器不是指针,这意味着-在调用一个方法之前,它将被创建一个结构体的副本,方法将在该副本上被调用。当然,你可以改变副本的值,但它不会影响原始值。