Go 指针法接收机中的重新分配
我对指针方法接收器和非指针方法接收器的理解是,第一个可以在方法中修改,下一个则不能 所以,下面的工作完全符合我的预期Go 指针法接收机中的重新分配,go,Go,我对指针方法接收器和非指针方法接收器的理解是,第一个可以在方法中修改,下一个则不能 所以,下面的工作完全符合我的预期 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)
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和未知/0
func (s *student) update() {
*s = student{"unknown", 0}
}
但是,我想用重新分配立即替换更新方法中的整个s。所以,我刚刚改变了更新方法,如下所示
func (s *student) update() {
s = &student{"unknown", 0}
}
并且它在主方法中不改变s,并打印双hongseok/13
func (s *student) update() {
*s = student{"unknown", 0}
}
上面的更改解决了这个问题
我认为没有语义上的区别。我遗漏了什么?在本例中,您将存储在
s
中的地址更改为不同的值
func (s *student) update() {
s = &student{"unknown", 0}
}
虽然使用指针被视为“通过引用传递”,但引用本身是一个与推送到调用堆栈上的任何其他值一样的值。返回main时,s
的值是该范围内的值。因此,为了给出更具体的信息,您使用s=1
调用main(为简单起见,调用地址1和地址2),在方法中,您在地址2处分配一个新的student
,然后设置s=2
,返回时,将从堆栈中弹出s
的版本,并将主要点中的s
切换到1
,但保持不变
在后一个例子中
func (s *student) update() {
*s = student{"unknown", 0}
}
您正在解引用s
并将新对象分配到该位置,覆盖现有内存。返回时,main中的指针仍指向同一位置,但内存中该位置的数据不同。因此,在本例中,您正在编写一个新的student
实例来寻址1
,因此当您返回时,您将在调用范围中看到新值。在第一个示例中:
func (s *student) update() {
s = &student{"unknown", 0}
}
您正在为s
分配一个全新的“指针值”,并且新的*s
指向一个新的学生
值。变量s
的作用域仅限于方法体,因此返回后没有副作用
在第二个例子中
func (s *student) update() {
*s = student{"unknown", 0}
}
您正在解引用
s
,并将*s
的值更改为指向一个新的student
值,或者换句话说,您正在将一个新的student
值放在s
指向的地址 我认为,你的主要问题是你对问题中出现的两个概念都不太理解
让我们从指针开始。当您不使用指针时,赋值意味着创建上一个值的简单副本。新值不与前一个值绑定。这意味着,如果更改旧值或新值,则不会影响第二个值。这对于基本类型(如int、bool、string)和结构是正常的
a := 1
b := a
a++ // a was changed, but value of b does not change at all
现在是指针,它指向内存中的一些空间。为了简单起见,我们创建了两个指针,它们都指向同一个地方
package main
import (
"fmt"
)
func main() {
type student struct {
name string
age int
}
p1 := &student{"hongseok", 13} // this mean create a new student, but we want only address of student, not value
p2 := p1
(*p1).age = 15 // because p1 and p2 point to same memory (*p2).age also changed
fmt.Println("1.", p2.age) // 15
p2.age = 32 // in golang I could write (*p2).ago or p2.ago this is the same
fmt.Println("2.", p1.age) // 32
fmt.Println("3.",p1, "==", p2)
fmt.Printf("4. %p == %p\n", p1, p2)
// But now I force point p2 to new place
p2 = &student{"another student", 12}
fmt.Println("5.", p1, "!=", p2)
fmt.Printf("6. %p == %p\n", p1, p2)
p1.age = 14 // does it influce p2.age? no! Why? Because it is in different address
fmt.Println("7.", p1, "!=", p2)
// but could is somehow force that point to same address ? Of course
p2 = p1 // p2 will point to same place as p1 and old value of p2 will be freed by garbage collector
}
不要混淆了——指针也可以指向指定的值
a := 42 // means allocate memory for integer, and we give that memory name "a"
p := &a
*p++ // it change value of a
a = 5 // and of course this change value of *p
现在回到方法,那个接收器是/不是指针。若方法的接收者是指针,那个就意味着你们可以改变它的值——就像我几行之前做的那个样
若方法接收器不是指针,这意味着-在调用方法之前,将创建一个struct副本,并对该副本调用该方法。您当然可以更改副本的价值,但它不会影响原始价值。如果没有第一句话,您的答案会更好。同意,没有理由说第一句话,我们都在学习。