What different does the * (pointer symbol) makes in the following Go method?

huangapple go评论81阅读模式
英文:

What different does the * (pointer symbol) makes in the following Go method?

问题

我正在遵循这个教程:https://github.com/astaxie/build-web-application-with-golang/blob/master/en/02.5.md。

我对指针还不太理解,所以这段代码让我有点困惑:func (h *Human) SayHi()。我尝试移除 *,输出结果却完全相同。为什么在这种情况下 * 是必需的?有人能给我一个使用下面代码的不同输出的例子吗?

package main
import "fmt"

type Human struct {
    name string
    age int
    phone string
}

type Student struct {
    Human // 匿名字段
    school string
}

type Employee struct {
    Human 
    company string
}

// 在 Human 中定义一个方法
func (h *Human) SayHi() {
    fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}

func main() {
    mark := Student{Human{"Mark", 25, "222-222-YYYY"}, "MIT"}
    sam := Employee{Human{"Sam", 45, "111-888-XXXX"}, "Golang Inc"}

    mark.SayHi()
    sam.SayHi()
}
英文:

I'm following this tutorial: https://github.com/astaxie/build-web-application-with-golang/blob/master/en/02.5.md.

I still don't understand pointers very well so this past confuses me a bit: func (h *Human) SayHi(). I tried removing the * and the output turned out to be exactly the same. Why is the * necessary in this case? Could someone give me an example of a different output with the code below?

package main
import "fmt"

type Human struct {
    name string
    age int
    phone string
}

type Student struct {
    Human // anonymous field
    school string
}

type Employee struct {
    Human 
    company string
}

// define a method in Human
func (h *Human) SayHi() {
    fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}

func main() {
    mark := Student{Human{"Mark", 25, "222-222-YYYY"}, "MIT"}
    sam := Employee{Human{"Sam", 45, "111-888-XXXX"}, "Golang Inc"}

    mark.SayHi()
    sam.SayHi()
}

答案1

得分: 3

它的区别在于该方法将在指向Human结构体的指针上定义,并且结构体中的所有方法将随后在指向的值上操作。

如果你去掉*,该方法将在调用方法的结构体副本上操作,因此在方法中对结构体进行的任何写操作对调用方法的代码都是无效的。

由于方法体只执行fmt.Printf并打印一些值,所以无论方法是在指针上定义还是不定义,实际上并没有太大的区别。

在某些情况下,为了并发安全起见,最好不要在指针上定义方法,因为这可能导致对底层结构体值的同时访问和写入。

英文:

The difference it does make is that the method will be defined on a pointer to a Human struct and all the methods in the struct will subsequently operate on the value pointed to.

If you were to loose the *, the method would operate on a copy of the struct you call the method on, so any write you'd do to the struct in the method would be useless for the code calling the method.

Since the method body only executes a fmt.Printf and prints some values, it does not really make a big difference if the method is defined on the pointer or not.

There are some cases where in the interest of concurrent-safety, you'd better not define methods on pointers, since this may lead to simultaneous access and writing of the underlying struct values.

答案2

得分: 1

使用指针接收器有两个原因:

  1. 首先,为了避免在每次方法调用时复制值(如果值类型是一个大的结构体,则更高效)。
  2. 其次,方法可以修改其接收器指向的值。

所以在你的例子中,如果你添加一个更改电话的方法,像这样:

func (h Human) ChangePhone() {
    h.phone = 'whatever'
}

在调用这个方法后,电话号码不会改变,这就是为什么要使用指针*的原因。

英文:

There are two reasons to use a pointer receiver:

  1. First, to avoid copying the value on each method call, more efficient if the value type is a large struct).
  2. Second, the method can modify the value that its receiver points to.

So in your example, if you add one more dump method to change phone like this:

func (h Human) ChangePhone() {
    h.phone = 'whatever'
}

The phone does not change after you call this method, that's why point * comes into play.

huangapple
  • 本文由 发表于 2015年1月14日 17:11:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/27939232.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定