繁体   English   中英

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

[英]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("This person should be initialized. Why is that not the case?")
    }
    fmt.Println(person)
}

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

在调用.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()函数的,所以在函数之外它没有任何效果。

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

type Person struct {
    name string
    age  int
}

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

person := NewPerson("John Doe")

通常,建议尝试以这样的方式定义您的类型,以便它们所谓的“零值” - 这种类型的变量在未明确初始化时获得的值 - 可以立即使用。 在你的情况下,对于Person的零值是否合理是值得怀疑的,因为它的age为0,这是完全合理的,并且name是空字符串,这可能是也可能不是。

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

Go编程语言规范

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

 type Point struct{ x, y float64 } func (p *Point) Scale(factor float64) { px *= factor py *= 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>

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM