跳转到主要内容
模块 5 · 第 5 课(共 5)课程中的25/50~10 min
模块课程(5/5)

“New...”构造函数模式

Go 没有 constructor 关键字。会议是一个工厂 返回正确初始化的值或指针的函数。由 名称通常称为 NewT (或 NewXxx)。

基本图案:NewT

Go
type User struct {
    Name string
    Age  int
}

func NewUser(name string, age int) *User {
    return &User{Name: name, Age: age}
}

u := NewUser("Ada", 36)
fmt.Println(u.Name)

相对于直接文字 &User{...} 的优点:

  • 您集中验证和默认值。
  • 您可以拥有未导出的字段并仅从构造函数填充它们。
  • 您可以在不破坏调用者的情况下更改实现。

带验证的构造函数:(*T,错误)

当初始化失败时,返回 (*T, error):

Go
import "errors"

func NewUser(name string, age int) (*User, error) {
    if name == "" {
        return nil, errors.New("nome obbligatorio")
    }
    if age < 0 {
        return nil, errors.New("eta non valida")
    }
    return &User{Name: name, Age: age}, nil
}

u, err := NewUser("Ada", 36)
if err != nil {
    // handle...
}

这是任何构造函数的惯用模式 前提条件:数据库连接、文件句柄、服务器配置等。

多个构造函数

如果您有多种构建“方式”,请使用描述性名称:

Go
func NewUser(name string) *User { ... }
func NewUserFromJSON(data []byte) (*User, error) { ... }
func NewAdmin() *User { ... }

Go 中没有重载:名称消除了歧义。

功能选项(高级一瞥)

当有很多可选参数时,惯用模式是 “功能选项”:

Go
type Option func(*Server)

func WithPort(p int) Option {
    return func(s *Server) { s.Port = p }
}

func WithTLS(cert, key string) Option {
    return func(s *Server) { s.Cert, s.Key = cert, key }
}

func NewServer(opts ...Option) *Server {
    s := &Server{Port: 8080} // default
    for _, opt := range opts {
        opt(s)
    }
    return s
}

s := NewServer(WithPort(9000), WithTLS("c.pem", "k.pem"))

它比字面意思更冗长,但可以很好地扩展许多可选的内容 参数并保留向后兼容性(添加新的 Option 不会破坏现有的调用者)。

当你不需要构造函数时

如果类型的零值已经有用,让调用者使用 直接字面意思。典型示例: sync.Mutex 没有构造函数, var m sync.Mutex 已经是一个随时可用的互斥体。与 bytes.Buffer 相同。

规则是:“让零值变得有用”。如果可以的话,不 强制构造函数。

尝试一下

锻炼#go.m5.l5.e1
尝试:0加载中...

编写工厂函数NewUser(name string,age int) *User,返回&User{Name: name, Age:age}。

正在加载编辑器...
显示提示

使用文字“&User{...}”返回一个指针。

3 次尝试后可用的解决方案

锻炼#go.m5.l5.e2
尝试:0加载中...

将 NewUser 转为 (name string) (*User, error): if name == '' return nil,Errors.New('nome obbligatorio')。

正在加载编辑器...
显示提示

如果有前提条件,则返回(*T, error),失败时返回nil + error。

3 次尝试后可用的解决方案

Quiz#go.m5.l5.e3
准备好

Go 中构造函数的惯用约定是什么?

Go
// Which signature is more idiomatic?
答案选项

回顾

  • 无 constructor:使用 NewT 函数(或同名包内的 New)。
  • 对于简单情况,返回 *T ; (*T, error) 具有前提条件或验证。
  • 出错时:返回 nil 作为指针,并返回解释性错误作为第二个值。
  • 严禁超载;使用描述性名称(NewUserFromJSON、NewAdmin)。
  • “使零值有用”:如果可以的话,构造函数是不必要的。
  • 许多可选参数的高级模式:功能选项。