vs.
Good
// func TestFoo(t *testing.T)f, err := ioutil.TempFile("", "test")if err != nil { t.Fatal("failed to set up test")}使用go.uber.org/atomic
使用sync/atomic包的原子操作对原始类型(int32 , int64等)进行操作(译注:指atomic包的方法名中均使用原始类型名 , 如SwapInt32等) , 因此很容易忘记使用原子操作来读取或修改变量 。
go.uber.org/atomic通过隐藏基础类型为这些操作增加了类型安全性 。此外 , 它包括一个方便的atomic.Bool类型 。
Bad
type foo struct { running int32 // atomic}func (f* foo) start() { if atomic.SwapInt32(&f.running, 1) == 1 { // already running… return } // start the Foo}func (f *foo) isRunning() bool { return f.running == 1 // race!}vs.
Good
type foo struct { running atomic.Bool}func (f *foo) start() { if f.running.Swap(true) { // already running… return } // start the Foo}func (f *foo) isRunning() bool { return f.running.Load()}三. 性能性能方面的特定准则 , 适用于热路径 。
优先使用strconv而不是fmt
将原语转换为字符串或从字符串转换时 , strconv速度比fmt快 。
Bad
for i := 0; i < b.N; i++ { s := fmt.Sprint(rand.Int())}BenchmarkFmtSprint-4 143 ns/op 2 allocs/opvs.
Good
for i := 0; i < b.N; i++ { s := strconv.Itoa(rand.Int())}BenchmarkStrconv-4 64.2 ns/op 1 allocs/op避免字符串到字节的转换
不要反复从固定字符串创建字节slice 。相反 , 请执行一次转换并捕获结果 。
Bad
for i := 0; i < b.N; i++ { w.Write([]byte("Hello world"))}BenchmarkBad-4 50000000 22.2 ns/opvs.
Good
data := []byte("Hello world")for i := 0; i < b.N; i++ { w.Write(data)}BenchmarkGood-4 500000000 3.25 ns/op四. 样式
相似的声明放在一组
Go语言支持将相似的声明放在一个组内:
Bad
import "a"import "b"vs.
Good
import ( "a" "b")这同样适用于常量、变量和类型声明:
Bad
const a = 1const b = 2var a = 1var b = 2type Area float64type Volume float64vs.
Good
const ( a = 1 b = 2)var ( a = 1 b = 2)type ( Area float64 Volume float64)仅将相关的声明放在一组 。不要将不相关的声明放在一组 。
Bad
type Operation intconst ( Add Operation = iota + 1 Subtract Multiply ENV_VAR = "MY_ENV")vs.
Good
type Operation intconst ( Add Operation = iota + 1 Subtract Multiply)const ENV_VAR = "MY_ENV"分组使用的位置没有限制 , 例如:你可以在函数内部使用它们:
Bad
func f() string { var red = color.New(0xff0000) var green = color.New(0x00ff00) var blue = color.New(0x0000ff) ...}vs.
Good
func f() string { var ( red = color.New(0xff0000) green = color.New(0x00ff00) blue = color.New(0x0000ff) ) ...}import组内的包导入顺序
应该有两类导入组:
- 标准库
- 其他一切
Bad
import ( "fmt" "os" "go.uber.org/atomic" "golang.org/x/sync/errgroup")vs.
Good
import ( "fmt" "os" "go.uber.org/atomic" "golang.org/x/sync/errgroup")包名
当命名包时 , 请按下面规则选择一个名称:
- 全部小写 。没有大写或下划线 。
- 大多数使用命名导入的情况下 , 不需要重命名 。
- 简短而简洁 。请记住 , 在每个使用的地方都完整标识了该名称 。
- 不用复数 。例如net/url , 而不是net/urls 。
- 不是“common” , “util” , “shared”或“lib” 。这些是不好的 , 信息量不足的名称 。
函数名
我们遵循Go社区关于使用MixedCaps作为函数名的约定 。有一个例外 , 为了对相关的测试用例进行分组 , 函数名可能包含下划线 , 如: TestMyFunction_WhatIsBeingTested 。
包导入别名
如果程序包名称与导入路径的最后一个元素不匹配 , 则必须使用导入别名 。
import ( "net/http" client "example.com/client-go" trace "example.com/trace/v2")在所有其他情况下 , 除非导入之间有直接冲突 , 否则应避免导入别名 。
Bad
import ( "fmt" "os" nettrace "golang.net/x/trace")vs.
Good
import ( "fmt" "os" "runtime/trace" nettrace "golang.net/x/trace")
推荐阅读
- R语言完美重现STAMP结果图
- 天黑黑孙燕姿在线试听 孙燕姿天黑黑是什么语言
- C 语言实现的跨平台开发库 TBOX
- TypeScript编码指南
- js中对字符串进行base64编码和解码
- 家庭语言暴力危害不容忽视
- 在C语言中如何高效地复制和连接字符串?
- 「C语言」常用算法
- C语言有多少个关键字,你知道吗?
- 一文搞懂Python字符编码问题,值得收藏
