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

Posted

技术标签:

【中文标题】在指针方法 Go 中初始化指针接收器【英文标题】:Initialize pointer receiver in pointer method 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 【参考方案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)

【讨论】:

以上是关于在指针方法 Go 中初始化指针接收器的主要内容,如果未能解决你的问题,请参考以下文章

Go语言基础:结构体

Go基础4

Go基础4

Go基础4

go语言之指针

Go-常识补充-切片-map(类似字典)-字符串-指针-结构体