这是Go常见错误系列的第14篇:过度使用getter和setter方法。
素材来源于Go布道者,现Docker公司资深工程师Teiva Harsanyi。
本文涉及的源代码全部开源在:Go常见错误源代码,欢迎大家关注公众号,及时获取本系列最新更新。
写Java或者C++的人,可能会习惯下面的编程模式:
这是一种数据封装模式,在Java和C++里被广泛使用。
但是在Go语言里,官方从来没有建议使用getter和setter,我们可以直接访问结构体里的成员变量。
成员变量的可见性通过结构体标识符首字母大小写以及成员变量首字母大小写来控制到package这个层面。
举个Go标准库里的time.Timer结构体的例子:
// The Timer type represents a single event.
// When the Timer expires, the current time will be sent on C,
// unless the Timer was created by AfterFunc.
// A Timer must be created with NewTimer or AfterFunc.
type Timer struct {
C <-chan Time
r runtimeTimer
}
Timer结构体定义如上所示,里面有一个成员变量C用于接收Timer到点后的当前时间。
Timer和C都是大写,所以我们可以直接在下面的代码里访问Timer里的成员变量C拿到当前时间。
package main
import (
"fmt"
"time"
)
func main() {
// print current time
fmt.Println(time.Now())
// NewTimer creates a new Timer that will send
// the current time on its channel after at least duration d.
timer := time.NewTimer(5 * time.Second)
// print current time
fmt.Println(<-timer.C)
}
上面程序执行结果是:
2022-11-06 13:07:07.706011 +0800 CST m=+0.000174256
2022-11-06 13:07:12.709128 +0800 CST m=+5.003141645
这种写法当然不是Go官方所预期的,因为成员变量C一般来说是不直接对外访问。
如果C暴露了可以对外访问,那我们甚至修改C的值,导致程序出错。
尽管不推荐这种写法,但是通过这个例子,我们可以知道如下事实:
Go标准库里对于结构体里不应该修改的字段,也没有使用getter和setter方法。
尽管Go官方没有使用getter和setter,但是从另一方面来说,在一些特定场景下使用getter和setter是有好处的。
Go语言里如果要使用getter和setter方法,有一些命名规范需要遵循。
假设我们要对结构体里的成员变量balance增加getter和setter方法,那么规范如下:
示例如下:
currentBalance := customer.Balance()
if currentBalance < 0 {
customer.SetBalance(0)
}
文章和示例代码开源在GitHub: Go语言初级、中级和高级教程。
公众号:coding进阶。关注公众号可以获取最新Go面试题和技术栈。
个人网站:Jincheng’s Blog。
知乎:无忌。
我为大家整理了一份后端开发学习资料礼包,包含编程语言入门到进阶知识(Go、C++、Python)、后端开发技术栈、面试题等。
关注公众号「coding进阶」,发送消息 backend 领取资料礼包,这份资料会不定期更新,加入我觉得有价值的资料。
发送消息「进群」,和同行一起交流学习,答疑解惑。