我正在学习Go,而且我对何时使用指针感到有点困惑。具体来说,从函数返回struct
时,何时返回结构实例本身是合适的,何时返回指向结构的指针是适当的?
示例代码:
type Car struct {
make string
model string
}
func Whatever() {
var car Car
car := Car{"honda", "civic"}
// ...
return car
}
我想要返回指针的情况是什么,以及不想要的地方?有一个很好的经验法则吗?
答案 0 :(得分:14)
您需要记住两件事,即性能和API。
如何使用汽车?它是一个有状态的对象吗?它是一个大型结构吗?不幸的是,当我不知道汽车是什么时,我们无法回答。说实话,最好的方法是看别人做什么并复制它们。最终,你对这种事情有了感觉。我现在将描述标准库中的三个示例,并解释为什么我认为他们使用了他们所做的事情。
hash/crc32
:crc32.NewIEEE()
函数返回一个指针类型(实际上是一个接口,但底层类型是一个指针)。散列函数的实例具有状态。当您将信息写入散列时,它会对数据进行汇总,因此当您调用Sum()
方法时,它将为您提供该实例的状态。
time
:time.Date
函数返回Time
结构。为什么?时间是一个时间。它没有国家。它就像一个整数,你可以比较它们,在它们上预先形成数学等等.API设计师决定对时间进行修改不会改变当前时间而是创建一个新时间。作为图书馆的用户,如果我想从现在开始一个月的时间,我会想要一个新的时间对象,而不是改变我现有的时间对象。时间也只有3个字。换句话说,它很小,使用指针不会有性能提升。
math/big
:big.NewInt()是一个有趣的问题。我们非常同意当您修改big.Int
时,您通常会想要一个新的big.Int
。 {{1}}没有内部状态,为什么它是指针?答案就是表现。程序员意识到大赌注......很大。每次进行数学运算时不断分配可能不切实际。因此,他们决定使用指针并允许程序员决定何时分配新空间。
我已回答你的问题吗?可能不是。这是一个设计决策,您需要根据具体情况来确定。我在设计自己的库时使用标准库作为指导。这完全取决于判断以及您希望客户端代码如何使用您的类型。
答案 1 :(得分:2)
通常,当你想模仿一个面向对象的样式时,你有一个“对象”来存储可以改变对象的状态和“方法”,那么你将有一个“构造函数”函数返回指向结构(将其视为与其他OO语言一样的“对象引用”)。 Mutator方法必须是指向结构类型的方法而不是结构类型本身的方法,以便更改“对象”的字段,因此有一个指向结构而不是结构的指针很方便值本身,以便所有“方法”都在其方法集中。
例如,在Java中模仿这样的东西:
class Car {
String make;
String model;
public Car(String myMake) { make = myMake; }
public setMake(String newMake) { make = myMake; }
}
你经常会在Go中看到类似的东西:
type Car struct {
make string
model string
}
func NewCar(myMake string) *Car {
return &Car{myMake, ""}
}
func (self *Car) setMake(newMake string) {
self.make = newMake
}
答案 2 :(得分:1)
非常糟糕,在特定情况下可能会出现例外情况: