在使用静态类型构造函数时是否有任何明显的缺点?

时间:2013-02-22 04:01:58

标签: 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似乎可以正常使用它,对我来说似乎更加明显和一致,没有额外的冗长。

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

2 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:2)

它并不是非常惯用的,如果你注意到的话可能会造成多余的垃圾。基本上你只是为你的对象创建一个Init方法。我不会使用很多构造函数,我自己倾向于为我的对象提供有效的零值,如果不能保持为真,则只使用构造函数。

在你的情况下,我认为我只是停止调用new方法,而是将其称为Init或Setup,以更好地反映它正在做的事情。这样可以避免让人们错误地了解它所做的事情。

编辑:

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

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

这可以避免多余的垃圾,并为您提供初始化方法。