Go Interesting
这里记录一些golang使用中的小细节,每次都像cgo那样单独写一篇有点太水了。
go:build
起因是用vscode上编辑boltdb的代码,每次ctrl+s保存之后就会在// +build xxx, xxx
前面加一句语义相同的//go:build blahblah
//go:build
是 Go 1.17 中引入的新条件编译指令。
它旨在替换// +
这个build tag,因为新语法带来了一些关键改进:
与其他现有 Go 指令和编译指示的一致性,
例如//go:generate
支持标准布尔表达式,
例如//go:build foo && bar
,而旧的 // +build
注释的语法不太直观。例如 AND 用逗号表示 // +build foo, bar
和 OR 用空格 // +build foo bar
go fmt 支持自动修复源文件中指令的错误位置,从而避免在指令和包语句之间不留空行的常见错误。
这两个构建指令将在几个 Go 版本中共存,以确保平滑过渡,如相关提案文件中所述(在 N = 17 以下,重点是我的):
Go 1.N 将开始转换。在 Go 1.N 中:
构建将开始更喜欢 //go:
用于文件选择的构建行。如果没有 // go: build
在一个文件中,那么任何 // +
构建行仍然适用。
如果Go文件包含//go: build
而没有 // +build
,构建将不再失败。
如果Go或程序集文件包含 // go: build
在文件中太过靠后,则构建将失败。 Gofmt 会将错位的 //go: build
和 // +build
行移动到文件中的正确位置。
Gofmt 将使用与其他 Go 布尔表达式(所有 && 和 || 运算符周围的空格)相同的规则来格式化//go:build
lines 中的表达式。
如果文件只包含// +build
行,gofmt 将在它们上方添加一个等效的//go:build
行。
如果文件同时包含 //go:build
和 // +build
行,gofmt 将考虑 //go:build
的真实来源并更新 // +build
行以匹配,从而保持与早期版本的 Go 的兼容性。 Gofmt 也会拒绝 //go:build
被认为太复杂而无法转换为 // +build
格式的行,尽管这种情况很少见。 (注意此项目符号开头的“If”。Gofmt 不会将 // +build
行添加到只有 //go:build
的文件中。)
go vet中的构建标签检查将添加对//go:build
约束的支持。当 Go 源文件包含 // go:build
和 // +build
具有不同含义时,它将失败。如果检查失败,可以运行 gofmt -w。
当 Go 源文件包含//go:build
, 但不包含//+build
, 且它的包含模块有一个go line列出 Go 1.N 之前的版本时,构建标签检查也会失败。如果检查失败,可以添加任何// +build
行,然后运行 gofmt -w,它将用正确的行替换它。或者可以将 go.mod go 版本升级到 Go 1.N。