在指针方法 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 中初始化指针接收器的主要内容,如果未能解决你的问题,请参考以下文章