Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Go 指针法接收机中的重新分配_Go - Fatal编程技术网

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副本,并对该副本调用该方法。您当然可以更改副本的价值,但它不会影响原始价值。

如果没有第一句话,您的答案会更好。同意,没有理由说第一句话,我们都在学习。