【go语言规范】关于setter和 getter

由于标准库实现了可以直接访问某些字段的结构体(和c一样)所以go 不需要java一样的 采用大量的getter 和 setter

这一点确实很有意思,也很容易让从Java转过来的人采取反模式

(以下内容来自Claude 和 书籍《go语言经典错误100例》

在结构体中,可以用首字母小写:包私有

首字母大写, 可导出

在 Go 语言中,getter 和 setter 的使用有一些特殊的约定和考虑。让我详细分析:

Go 语言中 Getter/Setter 的命名约定

go 复制代码
type User struct {
    name string    // 小写,包私有
    Age  int      // 大写,可导出
}

// Getter - 不需要 Get 前缀
func (u *User) Name() string {
    return u.name
}

// Setter - 通常使用 Set 前缀
func (u *User) SetName(name string) {
    u.name = name
}

优点

  1. 封装性

    • 保护内部状态
    • 控制数据访问
    • 可以添加验证逻辑
  2. 灵活性

    go 复制代码
    type Circle struct {
        radius float64
    }
    
    // 可以在 getter 中添加计算逻辑
    func (c *Circle) Area() float64 {
        return math.Pi * c.radius * c.radius
    }
  3. 向后兼容------调试更容易

    go 复制代码
    type User struct {
        firstName string
        lastName  string
    }
    
    // 可以改变内部实现而不影响外部调用
    func (u *User) Name() string {
        return u.firstName + " " + u.lastName
    }

缺点

  1. 代码冗余

    go 复制代码
    type Person struct {
        Name string  // 公开字段
    }
    
    // 如果字段已经是公开的,getter/setter 可能显得多余
    func (p *Person) Name() string { return p.Name }
    func (p *Person) SetName(name string) { p.Name = name }
  2. 性能开销

    • 方法调用比直接字段访问有更多开销
    • 在性能关键场景可能需要考虑
  3. 可能过度使用

    go 复制代码
    // 不推荐
    type Config struct {
        Port int
    }
    
    func (c *Config) GetPort() int { return c.Port }
    func (c *Config) SetPort(port int) { c.Port = port }

最佳实践

  1. 选择性使用

    go 复制代码
    type User struct {
        name    string // 需要控制访问的私有字段
        Profile string // 可以直接访问的公开字段
    }
    
    // 只为确实需要的字段提供 getter/setter
    func (u *User) Name() string { return u.name }
    func (u *User) SetName(name string) error {
        if name == "" {
            return errors.New("name cannot be empty")
        }
        u.name = name
        return nil
    }
  2. 添加业务逻辑

    go 复制代码
    type Account struct {
        balance float64
    }
    
    func (a *Account) Balance() float64 {
        return a.balance
    }
    
    func (a *Account) SetBalance(amount float64) error {
        if amount < 0 {
            return errors.New("balance cannot be negative")
        }
        a.balance = amount
        return nil
    }
  3. 使用接口定义行为

    go 复制代码
    type Reader interface {
        Read() string
    }
    
    type Writer interface {
        Write(data string) error
    }

使用建议

  1. 不要盲目添加

    • 只在真正需要时才添加 getter/setter
    • 如果字段可以公开,直接使用公开字段
  2. 注重实用性

    • 添加有意义的验证逻辑
    • 考虑并发安全性
  3. 保持简单

    • 避免过度设计
    • 遵循 Go 的简洁原则
  4. 考虑性能影响

    • 在性能敏感的场景权衡使用

记住:Go 不是传统的面向对象语言,不需要为每个字段都创建 getter/setter。应该根据实际需求选择性使用。

相关推荐
城管不管5 分钟前
重生——第十次面试之开源中国一面挂
java·linux·开发语言·算法·面试·职场和发展·开源
名字还没想好☜16 分钟前
Go 的 database/sql 连接池实战:SetMaxOpenConns 怎么配、连接泄漏怎么查
数据库·sql·golang·go·数据库连接池
圣殿骑士-Khtangc16 分钟前
Go-Docker多阶段构建与容器化最佳实践
golang
霸道流氓气质18 分钟前
Java开发者AI编程常用MCP、Skills、Rules全景汇总
java·开发语言·ai编程
zoujiahui_20181 小时前
Python 包与环境管理工具 uv
开发语言·python·uv
吴声子夜歌1 小时前
Java面试题——JVM(二)
java·开发语言·jvm
CRMEB1 小时前
商城大促活动策划全流程:从定目标到复盘四阶段
java·开发语言·人工智能·ai·开源·php
denglinqings1 小时前
Java开发从入门到精通所有课程
java·开发语言
程序猿阿森1 小时前
Python 闭包与装饰器:从入门到精通
开发语言·python·面试
余额瞒着我当琳2 小时前
C++--vector底层,leetcode118杨辉三角实战,对于传统reserve的坑点,迭代器失效
开发语言·c++