在指针方法Go中初始化指针接收器

时间:2017-03-17 10:36:45

标签: pointers go receiver

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

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()方法之后,人们会期望人被初始化(归零)。但事实并非如此。有人可以对此有所了解吗?

4 个答案:

答案 0 :(得分:7)

  

在调用.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()函数,因此在函数外部它没有任何效果。

答案 1 :(得分: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是一个空字符串,可能也可能没有。

答案 2 :(得分:1)

显然,方法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>

答案 3 :(得分:0)

NewPerson函数可以初始化为个人,也不能使用Person的struct和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)
}