2

我总是发现 go 中的 package.New() 语法很难使用。

建议是,如果一个包只包含一个类型,则使用 package.New() 创建一个实例;如果存在多种类型,则使用 package.NewBlah()。 http://golang.org/doc/effective_go.html#package-names

但是,如果您有一个带有 New() api 的现有包,则这种方法会失败,向包添加新的外部类型会破坏 api,因为您现在必须重命名此 NewFoo()。现在你必须去改变任何使用 New() 的东西,这很烦人。

......我只是对写这篇文章的审美不满:

import "other"
import "bar"
import "foo"

o := other.New()  // <-- Weird, what type am I getting? No idea.
x := bar.New()  
y := foo.NewFoo() // <-- Awkward, makes constructor naming look inconsistent   
z := foo.NewBar() 

所以,最近我一直在使用这种模式:

x := foo.Foo{}.New()   // <-- Immediately obvious I'm getting a Foo
y := foo.Bar{}.New()   // <-- Only an additional 3 characters on NewBar{}
o := other.Foo{}.New() // <-- Consistent across all packages, no breakage on update

模块的定义如下:

package foo

type Foo struct {
  x int
}

func (s Foo) New() *Foo {
  // Normal init stuff here
  return &s // <-- Edit: notice the single instance is returned 
}

type Bar struct {
}

func (Bar) New() *Bar {
  return &Bar{} // <-- Edit: Bad, results in double alloc. Not like this. 
}

Godoc 似乎可以很好地使用它,而且对我来说似乎更明显和一致,没有额外的冗长。

所以,问题:这有什么明显的缺点吗?

4

2 回答 2

2

是的,它有一个缺点。这种方法可能会产生不必要的垃圾——取决于特定 Go 编译器实现的优化有多好。

于 2013-02-22T04:25:39.010 回答
2

正如您所注意到的,这并不是非常惯用的,如果做得不好,可能会产生过多的垃圾。本质上,您只是为您的对象创建一个 Init 方法。我自己并不使用很多构造函数,我倾向于为我的对象使用有效的零值,并且仅在不成立时才使用构造函数。

在你的情况下,我想我会停止调用 new 方法,而是调用它 Init 或 Setup 以更好地反映它在做什么。这将避免让人们对它在做什么有错误的想法。

编辑:

我应该在这里更详细。调用方法 Init 或 Setup 然后在零值上使用它会更好地反映消费者正在发生的事情。例如

f := &foo{}
f.Init()

这避免了过多的垃圾,并为您提供了您所描述的初始化方法。

于 2013-02-22T05:14:36.410 回答