0. GO语言值和指针的区别在于函数传值还是传引用
1. 《理解GO协程调度的本质》
一篇发在腾讯技术工程公众号上的文章,很少见的把GO协程讲的这么明白的了。
2. 《100 个 Go 语言典型错误》
(法)Teiva Harsanyi(泰瓦·哈尔萨尼) 著
了解一门语言的缺点,换一个角度看问题,可以更加深入的理解一门语言。
抱着这个想法我在知乎上找到了这本电子书 电子书
问题一: := 写起来太容易。
:= 和var一起用很容易导致变量隐藏问题。下面这个例子,外层的client始终是nil
问题二:不必要的嵌套。
我认为这个问题并不是GO独有的问题,但是这的确是一个优化的角度,即选择合适的Guardian Clause可以优化代码、提高可读性。
问题三:滥用 init 函数。
首先,init函数是什么?
init是用于初始化应用程序状态的函数,在初始化包的时候执行。
init函数不能被主动调用。
init缺点:
1. 不要依赖一个包内的多个文件中init函数的执行顺序(按照源文本首字母顺序)
2. init函数不能返回错误,只能panic,这可能是无法接受的。
3. init函数没有参数,因为如果要传参数,则需要使用全局变量。使用全局变量是一件很危险的事。
4. 如果要在这个文件中写测试代码,那么init函数会在测试代码之前运行。
我的思考:
应该严格限制init函数的用处,究竟有什么内容是适合写在init函数中的?
显然,问题就出在这句在初始化包时执行。如果是多个包呢?
- 比如main依赖redis,那么顺序为:redis的init -> main的init -> main剩余代码。
- 一个包内可能有多个init,比如 a.go和b.go都有init,那么会按照源文件的字母顺序执行: a的init -> b.init
- 甚至可以在一个文件定义多个init函数(真的不推荐这么做),看这个例子
- 你可能也见过一些在 import代码块中直接重命名为 `_` 的代码块,实际上这么做就是为了运行包中的init函数。main包 import _ "foo",意义为 在main之前运行 foo的init函数
问题四:GO不强制使用Getter和Setter.
完全不使用Getter/Setter或者过度滥用Getter/Setter都可能造成问题。
以time标准库为例:它让你直接访问public的成员来完成Getter和Setter。
当然,你可以全都设置为私有成员,例如:time.c,然后通过提供public的getter/setter函数。
type myData struct {
var balance int
}
func (m *myData) Balance() int {
return s.balance
}
func (m *myData) SetBalance(new value) {
s.balance = value
}