引入
Go 没有 class 也没有构造函数关键字,但创建结构体实例时经常需要做初始化——设置默认值、校验参数、初始化内部字段。Go 社区约定用 New 开头的函数来完成这些工作,形成了统一的构造函数模式。
正文
定义
定义
构造函数模式是 Go 社区约定的对象初始化方式。Go 没有内置构造函数,而是通过
New开头的普通函数来创建并初始化类型的实例。这种模式也叫工厂模式,调用方不需要了解内部细节,拿到手的就是一个可用的实例。
语法
// 返回指针
func New类型名(参数) *类型名 {
return &类型名{
字段: 初始值,
}
}
// 返回错误(初始化可能失败时)
func New类型名(参数) (*类型名, error) {
if 参数不合法 {
return nil, errors.New("参数错误")
}
return &类型名{字段: 初始值}, nil
}例子
基本 New 函数
type User struct {
Name string
Age int
Email string
}
func NewUser(name string, age int) *User {
return &User{
Name: name,
Age: age,
}
}
func main() {
u := NewUser("Alice", 25)
fmt.Println(u.Name, u.Age)
}NewUser 封装了创建逻辑,调用方不用关心 User 的字段细节。
带默认值
type Config struct {
Host string
Port int
Timeout int
}
func NewConfig(host string) *Config {
return &Config{
Host: host,
Port: 8080,
Timeout: 30,
}
}构造函数里设好默认值,调用方只传必要的参数。
带错误返回
type Server struct {
Addr string
}
func NewServer(addr string) (*Server, error) {
if addr == "" {
return nil, errors.New("地址不能为空")
}
return &Server{Addr: addr}, nil
}
func main() {
s, err := NewServer("")
if err != nil {
fmt.Println("创建失败:", err)
return
}
fmt.Println(s.Addr)
}初始化可能失败时,返回 (*类型, error),这是 Go 标准的错误处理模式。
带内部初始化
type Cache struct {
data map[string]string
}
func NewCache() *Cache {
return &Cache{
data: make(map[string]string),
}
}
func (c *Cache) Set(key, value string) {
c.data[key] = value
}
func main() {
c := NewCache()
c.Set("name", "Alice")
}map、slice、channel 等需要 make 初始化的字段,在构造函数里处理好,避免调用方拿到 nil。
多种构造方式
type Logger struct {
Level string
Output string
}
func NewLogger() *Logger {
return &Logger{
Level: "info",
Output: "stdout",
}
}
func NewLoggerWithLevel(level string) *Logger {
return &Logger{
Level: level,
Output: "stdout",
}
}没有函数重载,就用不同名字的 New 函数提供多种构造方式。
Options 模式
type Option func(*Server)
type Server struct {
Addr string
Timeout int
MaxConn int
}
func WithTimeout(t int) Option {
return func(s *Server) {
s.Timeout = t
}
}
func WithMaxConn(n int) Option {
return func(s *Server) {
s.MaxConn = n
}
}
func NewServer(addr string, opts ...Option) *Server {
s := &Server{
Addr: addr,
Timeout: 30,
MaxConn: 100,
}
for _, opt := range opts {
opt(s)
}
return s
}
func main() {
s := NewServer("localhost", WithTimeout(60), WithMaxConn(200))
}参数多时用 Options 模式,每个可选参数是一个函数,灵活且可扩展。
常见写法
| 写法 | 说明 |
|---|---|
func NewUser() *User | 基本构造函数 |
func NewServer(addr string) (*Server, error) | 带错误返回 |
func NewConfig(host string) *Config | 带默认值 |
func NewCache() *Cache | 带内部初始化 |
func NewXxx(opts …Option) *Xxx | Options 模式 |
func NewXxxWithLevel(l string) *Xxx | 多种构造方式 |
特点
- Go 没有构造函数关键字,用
New开头的普通函数代替 - 构造函数通常返回指针
*类型 - 初始化可能失败时返回
(*类型, error) - 内部需要
make的字段(map、channel 等)在构造函数里初始化 - 没有函数重载,用不同函数名区分多种构造方式
- Options 模式适合参数多、可选参数多的场景
- 构造函数是社区约定,不是语言特性,但几乎所有 Go 项目都遵循
理解
Go 用简单的 New 函数替代了其他语言的构造函数,看起来朴素但够用。好处是初始化逻辑就是一个普通函数,容易测试、容易理解。记住在构造函数里处理好默认值和需要 make 的字段,调用方拿到的就是一个随时可用的实例。
引出
构造函数创建实例,方法绑定行为,那怎么让不同类型有统一的”能力描述”?这就是 Go 接口 的作用——定义一组方法签名,任何实现了这些方法的类型都算实现了这个接口。