Skip to content
自由人的 BLOG

《Go 语言实战》笔记

Go, 代码, 语法, 读书
阅读量

上周末翻完了《Go 语言实战》这本书,还不错,篇幅不大,内容实用。书中有很多内容是这样写的:先给出一大段代码,然后一点一点拆解分析,稍微有些啰嗦。我先把 A Tour of Go 过了一遍,再看这本书算是更深入了一点。

看书过程中,标注了一些之前忽略或者生僻或者需要刻意重复练习的——或者是有趣的——知识点(自然是不全面的),整理在这里。

init 函数

程序中每个代码文件里的 init 函数都会在 main 函数执行前调用。

一个常见的用途:在 init 函数里配置日志参数,让程序一开始就能用 log 包按格式进行输出。

强制风格

为了让程序的可读性更强,Go 编译器不允许声明导入某个包却不使用。下划线 _ 让编译器接受这类导入,并且调用对应包内的所有代码文件里定义的 init 函数。

不仅不允许导入包却不使用,也不允许声明了变量后不使用。

Go 在语法格式上也有一些区别于其他语言的强制规定

  • 行尾不能加分号
  • 左大括号 { 不能另起一行
  • if 判断式 和 for 循环不用小括号括起来

与其让编译器告警,不如直接失败更有意义。

违法了上面提到的各项规则,都会让代码编译失败。

命名导入

如果导入的包有重名的,或者说是要导入两个一样名字的包(我觉得这通常不是什么好事),可以给导入的包另起一个名字,来解决命名冲突。

Go

数组, slice, map

数组和 slice

一旦声明,数组里存储的数据类型和数组长度就不能改变了。

同样类型的数组可以赋值给另一个数组。

这里说的同样类型,是指数组长度和每个元素的类型都相同。例如下面例子中的数组 a,它的类型是“拥有 4 个 int 元素的数组”。

根据内存和性能来看,在函数间传递数组是一个开销很大的操作。

如果函数的参数是数组,在函数间传递数组时,整个数组都会被复制一遍。

slice 作为函数参数时,不用担心像数组那样的开销。

由于与 slice 关联的数据包含在底层数组里,不属于 slice 本身,所以将 slice 复制到任意函数的时候,对底层数组大小都不会有影响。

一个例子

a, bc 类型相同,都是“包含 4 个 int 元素的数组”。其中 a 中的四个元素被初始化了四个不同的值,bc 中的元素都是零值。

d 是一个 []int 类型的 slice

这一段代码的输出是

可以看出把数组 c 复制给 x 时,整个数组都被复制了一遍,之后 xc 就没关联了,修改 x 中元素的值,不影响 c

这段代码的输出是

dy 的地址不同,不是同一个 slice,但是它们的底层数据是一样的,所以 d[0]y[0] 的地址相同,修改 y 中元素的值,也修改了 b 中元素的值,反之亦然。

map

map 的键可以是内置类型,也可以是结构体,只要这个值能用 == 运算符做比较。slice、函数以及包含 slice 的结构体,具有引用语义,不能作为 map 的键。

map 的值可以是任意类型,任意的值。

range 返回的不是对元素的引用

range 迭代(遍历)slice 时,range 创建了每个元素的副本,而不是直接返回对该元素的引用。

下面是我电脑上的一次输出结果,可以看到每次迭代的 v 的地址是一样的。

golang 面试题这里的第二个题目与这个点相关。

嵌入类型

嵌入类型是将已有的类型直接声明在新的结构类型里

输出结果是

由于内部类型的提升,内部类型实现的接口会自动提升到外部类型。这意味着由于内部类型的实现,外部类型也同样实现了这个接口。

具体到上面代码中,外部类型是 admin,内部类型是 useradmin 并没有实现 write 方法,调用了 usewrite 方法。如果外部类型实现了 write 方法,就不会去调用内部类型的 write 方法了。

输出就变成了

关键字 iota

这是个有点古怪的关键字。乍一看我以为是 itoaatoi 之类的函数,其实它是在生命 const 变量时用的,itoa 起到自增的作用。

In some programming languages (e.g., A+, APL, C++, Go[6]) iota (either as a lowercase symbol ι or as a keyword iota) is used to represent and generate an array of consecutive integers. For example, in APL ι4 gives 1 2 3 4.

Ultimate Visual Guide to Go Enums 这篇文章有很详细的讲述。

Golang WiKi 上提到的两个例子:

Weekday enum example - How iota is calculated


每种编程语法都可能有些坑,但是通常来说,刻意去制造出现“坑”的上下文,刻意纠结语法细节, 是没有必要的,甚至是有害的。在实际工作中,这是种要尽量避免的情况。

对于编程语言的学习,最好的教程还是官方的各种文档,不是要一气看完,边写边查也未尝不可。写得多了,自然水到渠成。

← 最近两周的生活和工作← 上一篇