在Go构造函数中返回值vs指针



在go中构建一个简单的对象时,这些选项之间的区别是什么?

func NewGender(value string) Gender {
    return Gender{strings.TrimSpace(value)}
}
func NewGender(value string) *Gender {
    return &Gender{strings.TrimSpace(value)}
}

这是一个非常广泛的问题,它在很大程度上取决于API的其余部分。所以这里有一些你在选择时可能需要考虑的事情(没有特定的顺序):

  • 不必要的指针会给GC带来更多的工作。通过返回指针(一个单词)而不是结构体(从0到多个单词),您可能会赢得一些时间,但其中一些时间可能稍后会被GC扫描所消耗。

  • 指针也可以表示事物的存在或不存在,尽管通常最好使用逗号-ok来表示,否则会返回错误。

  • 说到错误,如果您返回带有错误的nil,则错误被忽略的可能性较小(因为nil指针解引用将导致panic)。然而,我不认为那些忽略错误的人是你真正应该考虑的问题。

  • 如果你需要某种形式的跟踪(例如,检查构造函数创建的所有实例的可能性),你必须返回一个指针,以便检查器可以看到对值的所有更改。

  • 如果大多数类型的方法都有一个指针接收器,或者API中的大多数函数接受指向该类型的指针而不是值,那么返回指针更符合人体工程学。

返回的第一项是一个值,第二项是一个指针。指针的工作方式很像C或c++中的指针,只是它指向的值会像c#或Java一样被垃圾收集。Go在这两种范式之间提供了某种折衷。指针是显式的和公开的,但是它仍然被垃圾收集。以下是一些比较明显的区别:

1)如果你将值传递给一个方法或者它是接收者(这经常令人困惑),你将无法修改它的值,它将是一个"按值传递",就像在其他语言中你修改副本一样。是的,即使方法func (g Gender) ChangeGender()也不会改变调用它的对象的性别。https://play.golang.org/

2)只能调用为该类型定义的方法。例如,如果你有g *Gender,你想调用上面的ChangeGender方法,你将无法不解引用你的指针,就像在C/c++中一样。

3)按值传递的替代方法是按引用传递,你可能知道它是如何工作的,但如果你不知道,我将解释。如果你有一个方法func (g *Gender) ModifyGender()和一个实例g := &Gender{},那么当调用ModifyGender时,一个操作系统字大小的指针将被作为参数压入堆栈,而不是值本身,方法将使用该地址修改那里的内存,当控制返回给调用者时持久化更改。这可以极大地提高性能,如果你的方法工作的对象有很大的内存占用。

我不打算谈论性能。这应该给您足够的信息来考虑它如何在您的应用程序中工作。

正如@evanmcdonnal所说,选择与如何使用结构体更相关。

  • 如果你的结构是信息只有,你不打算改变它以后,保持它简单,并返回一个值(如自定义错误结构),如果你的结构是真的很大,但你不打算改变它使用指针(如RGB矩阵)

  • 如果你计划在你的程序工作流程中改变你的结构,使用指针。

最新更新