前言
这是 Go 常见谬误系列的第 14 篇:适度应用 getter 和 setter 办法。
素材来源于 Go 布道者,现 Docker 公司资深工程师 Teiva Harsanyi。
本文波及的源代码全副开源在:Go 常见谬误源代码,欢送大家关注公众号,及时获取本系列最新更新。
常见谬误和最佳实际
现状
写 Java 或者 C ++ 的人,可能会习惯上面的编程模式:
- 将不心愿内部间接拜访的类成员变量设置为 private 公有成员。
- 在类里定义 public 的 get 和 set 办法,用于内部获取和批改这个成员变量的值。get 办法咱们叫做 getter,set 办法叫做 setter。
这是一种数据封装模式,在 Java 和 C ++ 里被宽泛应用。
然而在 Go 语言里,官网素来没有倡议应用 getter 和 setter,咱们能够间接拜访构造体里的成员变量。
成员变量的可见性通过构造体标识符首字母大小写以及成员变量首字母大小写来管制到 package 这个层面。
- 如果构造体要被其它 package 应用,那构造体的标识符或者说构造体的名称首字母要大写。
- 如果构造体的成员要被其它 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 是有益处的。
- getter 和 setter 暗藏了外部实现,咱们能够本人灵便管制该裸露哪些货色。
- 如果成员变量的值产生了预期之外的变动,那通过 getter 和 setter,咱们能够不便做一些调试,更快发现问题。
Go 语言里如果要应用 getter 和 setter 办法,有一些命名标准须要遵循。
假如咱们要对构造体里的成员变量 balance 减少 getter 和 setter 办法,那么标准如下:
- getter 办法应该被命名为 Balance(而不是 GetBalance)。
- setter 办法应该被命名为 SetBalance。
- 首字母大写是因为要被内部 package 应用,要大写来保障可见性。
示例如下:
currentBalance := customer.Balance()
if currentBalance < 0 {customer.SetBalance(0)
}
总结
- Java/C++ 等语言里罕用的 getter 和 setter,在 Go 语言里并不是常规和标准。
- 然而如果发现有下面讲到的须要应用到 getter 和 setter 的场景,那还是应该应用的,而不是齐全不必。
- getter 和 setter 办法命名参考下面提到的命名标准。
举荐浏览
- Go 面试题系列,看看你会几题?
- Go 常见谬误第 1 篇:未知枚举值
- Go 常见谬误第 2 篇:benchmark 性能测试的坑
- Go 常见谬误第 3 篇:go 指针的性能问题和内存逃逸
- Go 常见谬误第 4 篇:break 操作的注意事项
- Go 常见谬误第 5 篇:Go 语言 Error 治理
- Go 常见谬误第 6 篇:slice 初始化常犯的谬误
- Go 常见谬误第 7 篇:不应用 -race 选项做并发竞争检测
- Go 常见谬误第 8 篇:并发编程中 Context 应用常见谬误
- Go 常见谬误第 9 篇:应用文件名称作为函数输出
- Go 常见谬误第 10 篇:Goroutine 和循环变量一起应用的坑
- Go 常见谬误第 11 篇:意外的变量遮蔽(variable shadowing)
- Go 常见谬误第 12 篇:如何破解箭头型代码
- Go 常见谬误第 13 篇:init 函数的常见谬误和最佳实际
开源地址
文章和示例代码开源在 GitHub: Go 语言高级、中级和高级教程。
公众号:coding 进阶。关注公众号能够获取最新 Go 面试题和技术栈。
集体网站:Jincheng’s Blog。
知乎:无忌。
福利
我为大家整顿了一份后端开发学习材料礼包,蕴含编程语言入门到进阶常识(Go、C++、Python)、后端开发技术栈、面试题等。
关注公众号「coding 进阶」,发送音讯 backend 支付材料礼包,这份材料会不定期更新,退出我感觉有价值的材料。
发送音讯「进群」,和同行一起交流学习,答疑解惑。
References
- https://livebook.manning.com/…
- https://github.com/jincheng9/…