Initialize pointer receiver in pointer method Go

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

Initialize pointer receiver in pointer method Go

问题

如何使用指针方法初始化指针接收器?

package main

import "fmt"

type Person struct {
	name string
	age  int
}

func (p *Person) Born() {

	if nil == p {
		p = new(Person)
	}

}

func main() {

	var person *Person
	person.Born()
	if person == nil {
		fmt.Println("这个人应该被初始化。为什么不是这样?")
	}
	fmt.Println(person)
}

在调用.Born()方法(指针接收器)之后,人们期望person被初始化(清零)。但事实并非如此。有人能解释一下吗?

英文:

How can I initialize a pointer receiver with a pointer method?

package main

import "fmt"

type Person struct {
	name string
	age  int
}

func (p *Person) Born() {

	if nil == p {
		p = new(Person)
	}

}

func main() {

	var person *Person
	person.Born()
	if person == nil {
		fmt.Println("This person should be initialized. Why is that not the case?")
	}
	fmt.Println(person)
}

One would expect person to be initialized (zeroed) after calling .Born() method which is a pointer receiver. But that is not the case. Could someone shed some light on this?

答案1

得分: 17

在调用.Born()方法之后,人们会期望person被初始化(清零),而.Born()方法是一个指针接收器。

调用接收器上的方法假设接收器已经被初始化。

所以你需要初始化它:

var person *Person
person = &Person{}  // 将指针指向一个空的Person{}结构体

或者可以在一条语句中完成

var person = &Person{}

或者使用简写形式

person := &Person{}

你的预期的自我初始化失败的原因是:

func (p *Person) Born() {
    if nil == p {
        p = new(Person)
    }
}

是因为你对p的新赋值仅在Born()函数的作用域内有效,所以在函数外部它没有任何效果。

英文:

> One would expect person to be initialized (zeroed) after calling .Born() method which is a pointer receiver.

Calling a method on a receiver assumes that the receiver is already initialized.

So you need to initialize it:

var person *Person
person = &Person{}  // Sets the pointer to point to an empty Person{} struct

Or in a single statement:

var person = &Person{}

Or shorthand:

person := &Person{}

The reason your intended self-initialization is failing:

func (p *Person) Born() {
    if nil == p {
        p = new(Person)
    }
}

Is that your new assignment to p is scoped to the Born() function, so outside the function it has no effect.

答案2

得分: 2

显然,Born 方法不会初始化 person。参数通过将参数赋值给参数来传递值。

Go 编程语言规范

方法的类型是将接收器作为第一个参数的函数的类型。

type Point struct{ x, y float64 }

func (p *Point) Scale(factor float64) {
    p.x *= factor
    p.y *= factor
}

例如,方法 Scale 的类型是

func(p *Point, factor float64)

然而,以这种方式声明的函数不是方法。

在函数调用中,函数值和参数按照通常的顺序进行求值。在它们被求值之后,调用的函数的参数通过值传递给函数,并且被调用的函数开始执行。当函数返回时,返回参数通过值传递回调用函数。

为了说明,这里有各种形式的 Born 方法调用。p 的作用域仅限于方法或函数调用。

package main

import "fmt"

type Person struct {
    name string
    age  int
}

// 方法
func (p *Person) Born() {
    if nil == p {
        p = new(Person)
    }
}

// 方法作为函数
func Born(p *Person) {
    if nil == p {
        p = new(Person)
    }
}

func main() {

    // 初始方法调用形式
    {
        var person *Person
        person.Born()
        fmt.Println(person)
    }

    // 等效的按值调用形式
    {
        var person *Person
        {
            p := person
            p.Born()
        }
        fmt.Println(person)
    }

    // 等效的方法调用作为函数调用形式
    {
        var person *Person
        {
            p := person
            Born(p)
        }
        fmt.Println(person)
    }

    // 等效的方法调用作为内联函数形式
    {
        var person *Person
        {
            p := person
            if nil == p {
                p = new(Person)
            }
        }
        fmt.Println(person)
    }

}

输出:

<nil>
<nil>
<nil>
<nil>
英文:

Clearly, person will not be initialized by method Born. Parameters are passed by value through the assignment of arguments to parameters.

> The Go Programming Language
> Specification

>
> The type of a method is the type of a function with the receiver as
> first argument.
>
> type Point struct{ x, y float64 }
>
> func (p *Point) Scale(factor float64) {
> p.x *= factor
> p.y *= factor
> }
>
> For instance, the method Scale has type
>
> func(p *Point, factor float64)
>
> However, a function declared this way is not a method.
>
> In a function call, the function value and arguments are evaluated in
> the usual order. After they are evaluated, the parameters of the call
> are passed by value to the function and the called function begins
> execution. The return parameters of the function are passed by value
> back to the calling function when the function returns.

To illustrate, here are various forms of the Born method call. The scope of p is limited to the method or function call.

package main

import &quot;fmt&quot;

type Person struct {
	name string
	age  int
}

// Method
func (p *Person) Born() {
	if nil == p {
		p = new(Person)
	}
}

// Method as function
func Born(p *Person) {
	if nil == p {
		p = new(Person)
	}
}

func main() {

	// Initial method call form
	{
		var person *Person
		person.Born()
		fmt.Println(person)
	}

	// Equivalent method call by value form
	{
		var person *Person
		{
			p := person
			p.Born()
		}
		fmt.Println(person)
	}

	// Equivalent method call as function call form
	{
		var person *Person
		{
			p := person
			Born(p)
		}
		fmt.Println(person)
	}

	// Equivalent method call as inline function form
	{
		var person *Person
		{
			p := person
			if nil == p {
				p = new(Person)
			}
		}
		fmt.Println(person)
	}

}

Output:

&lt;nil&gt;
&lt;nil&gt;
&lt;nil&gt;
&lt;nil&gt;

答案3

得分: 1

我认为你需要的是"构造函数"或"工厂"函数:

type Person struct {
    name string
    age  int
}

func NewPerson(name string) *Person {
    return &Person{
        name: name,
    }
}

person := NewPerson("John Doe")

通常建议尝试以这样的方式定义类型,使得它们的所谓"零值"——即变量在没有显式初始化的情况下获得的值——可以立即使用。
在你的情况下,对于Person类型的零值是否合理是有问题的,因为它将具有age为0,这是完全合理的,而name为空字符串,这可能是可以接受的,也可能不可以。

英文:

I think what you need instead is "constructor" or "factory" function:

type Person struct {
    name string
    age  int
}

func NewPerson(name string) *Person {
    return &amp;Person{
        name: name,
    }
}

person := NewPerson(&quot;John Doe&quot;)

Generally, it's advised to try to define your types in such a way
so that their so-called "zero value"&mdash;the value a variable of this
type gets when it's not explicitly initialized otherwise&mdash;is ready
to be used right away.
In your case, it's questionable whether the zero value for Person is
sensible because it will have age of 0, which is perfectly reasonable,
and name being an empty string, which may or may not be OK.

答案4

得分: 0

NewPerson函数可以初始化一个人,而不是使用Person结构体和Born方法来获取一个新的人。

package main

import (
	"fmt"
	"time"
)

type Person struct {
	Name string
	Dob  time.Time
}

func NewPerson(name string, year, month, day int) *Person {
	return &Person{
		Name: name,
		Dob:  time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.Local),
	}
}

func (p *Person) GetAge() string {
	d := time.Since(p.Dob)
	return fmt.Sprintf("%s's age is %d", p.Name, int(d.Hours()/24/365))
}

func (p *Person) Born() {
	p.Name = "New born (unnamed)"
	p.Dob = time.Now()
}

func main() {
	joe := NewPerson("Joe", 1999, 12, 31)
	joeAge := joe.GetAge()
	fmt.Println(joeAge)

	newPerson := &Person{}
	newPerson.Born()
	newPersonAge := newPerson.GetAge()
	fmt.Println(newPersonAge)
}

请注意,这是一个Go语言的代码示例,用于演示如何使用NewPerson函数初始化一个人,并使用GetAge方法获取年龄。Born方法用于将人的姓名设置为"New born (unnamed)",并将出生日期设置为当前时间。在main函数中,我们创建了一个名为"Joe"的人,并打印出他的年龄。然后,我们创建了一个新的人,并打印出他的年龄。

英文:

NewPerson function can initialize as a person, nor using Person struct and Born method to get a new Person.

package main

import (
	&quot;fmt&quot;
	&quot;time&quot;
)

type Person struct {
	Name string
	Dob  time.Time
}

func NewPerson(name string, year, month, day int) *Person {
	return &amp;Person{
		Name: name,
		Dob:  time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.Local),
	}
}

func (p *Person) GetAge() string {
	d := time.Since(p.Dob)
	return fmt.Sprintf(&quot;%s&#39;s age is %d&quot;, p.Name, int(d.Hours()/24/365))
}

func (p *Person) Born() {
	p.Name = &quot;New born (unnamed)&quot;
	p.Dob = time.Now()
}

func main() {
	joe := NewPerson(&quot;Joe&quot;, 1999, 12, 31)
	joeAge := joe.GetAge()
	fmt.Println(joeAge)

	newPerson := &amp;Person{}
	newPerson.Born()
	newPersonAge := newPerson.GetAge()
	fmt.Println(newPersonAge)
}

huangapple
  • 本文由 发表于 2017年3月17日 18:36:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/42855240.html
匿名

发表评论

匿名网友

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

确定