【问题标题】:Initialize pointer receiver in pointer method Go在指针方法 Go 中初始化指针接收器
【发布时间】:2017-03-17 10:36:45
【问题描述】:

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

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)
}

人们会期望在调用作为指针接收器的 .Born() 方法之后将人初始化(归零)。但事实并非如此。有人可以对此有所了解吗?

【问题讨论】:

  • var person *Person 没有意义。 Person 是一个结构体。
  • @Gravy 当然有道理。它将person 定义为指向Person 结构的未初始化指针。在这种情况下,这不是 OP 想要的。
  • person 类型为 pointer to Person 的初始化为零 - nil

标签: pointers go receiver


【解决方案1】:

人们会期望在调用作为指针接收器的 .Born() 方法后初始化(归零)人。

在接收器上调用方法假定接收器已经初始化。

所以你需要初始化它:

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

或者在单个语句中:

var person = &Person{}

或简写:

person := &Person{}

您预期的自初始化失败的原因:

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

您对p 的新分配是否仅限于Born() 函数,所以在函数之外它不起作用。

【讨论】:

  • 非常感谢 Flimzy 的回复。
【解决方案2】:

我认为您需要的是“构造函数”或“工厂”函数:

type Person struct {
    name string
    age  int
}

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

person := NewPerson("John Doe")

一般来说,建议尝试以这种方式定义您的类型 所以他们所谓的“零值”——这个值的一个变量 类型在未显式初始化时获取 - 准备就绪 立即使用。 在您的情况下,Person 的零值是否为 明智的,因为它的age 为 0,这是完全合理的, 和name 是一个空字符串,可能会也可能不会。

【讨论】:

  • 谢谢 Kostix。我的问题纯粹是教育性的,我知道工厂模式是要走的路。
【解决方案3】:

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

The Go Programming Language Specification

方法的类型是函数的类型,接收者为 第一个参数。

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
}

// 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)
    }

}

输出:

<nil>
<nil>
<nil>
<nil>

【讨论】:

    【解决方案4】:

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

    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)
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-11-09
      • 1970-01-01
      • 2011-04-10
      • 2010-10-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多