Go代码规范梳理

Go代码规范(Code Review)

总结几个开发过程中经常会犯的代码规范错误

成都网络公司-成都网站建设公司创新互联公司10余年经验成就非凡,专业从事成都网站设计、网站建设,成都网页设计,成都网页制作,软文推广一元广告等。10余年来已成功提供全面的成都网站建设方案,打造行业特色的成都网站建设案例,建站热线:13518219792,我们期待您的来电!

参考链接:https://learnku.com/go/wikis/

注释语句

// Request 表示运行命令的请求。
type Request struct { ...

// Encode 将 req 的 JSON 编码写入 w 。
func Encode(w io.Writer, req *Request) { ...

上下文

大部分使用上下文的函数都要将其作为第一个参数

func F(ctx context.Context, /* 其他参数 */) {}

不建议把上下文作为成员添加到结构类型中

// 不建议写法
type MyContext struct {
    ctx context.Context
}

Crypto Rand

不要使用 math/rand 来生成密钥,即使是一次性密钥。在没有种子(seed)的情况下,生成器是完全可以被预测的。请使用 crypto/rand 的 Reader 作为替代

func Key() string {
	buf := make([]byte, 16)
	_, err := rand.Read(buf)
	if err != nil {
		panic(err) // 出于随机性,永远都不会发生
	}
	return fmt.Sprintf("%x", buf)
	// or hex.EncodeToString(buf)
	// or base64.StdEncoding.EncodeToString(buf)
}

func main() {
	fmt.Println(Key())
}
//输出
//4799b801ecfaedb03cf8da

声明空的切片

当声明一个空 slice 时,倾向于用

var t []string

而不是

t := []string{}

前者声明了一个 nil slice 值,而后者声明了一个非 nil 但是零长度的 slice。两者在功能上等同,len 和 cap 均为零,而 nil slice 是首选的风格。

请注意,在部分场景下,首选非 nil 但零长度的切片,例如编码 JSON 对象时(nil 切片编码为 null,而则 []string{} 可以正确编码为 JSON array [])。

包注释

/*
Package template implements data-driven templates for generating textual
output such as HTML.
....
*/
package template

如果包很简单,包注释可以很简短。

// Package math provides basic constants and mathematical functions.
package math

包名

对包中名称的所有引用都将使用包名完成,因此可以从标识符中省略该名称。 例如,如果你正在使用 chubby包,则不需键入 ChubbyFile ,因为客户端会将其写为 chubby.ChubbyFile。 相反,命名为 File 的这种方式,客户端会将它写为 chubby.File。 避免使用像 utilcommonmiscapitypesinterfaces 这样无意义的包名。

不要Panic

错误信息

即使用 fmt.Errorf("something bad") 而不要使用 fmt.Errorf("Something bad")

包的导入

避免包重命名导入,防止名称冲突;好的包名称不需要重命名。如果发生命名冲突,则更倾向于重命名最接近本地的包或特定于项目的包。

包导入按组进行组织,组与组之间有空行。标准库包始终位于第一组中。

package main

import (
    "fmt"
    "hash/adler32"
    "os"

    "appengine/foo"
    "appengine/user"

    "github.com/foo/bar"
    "rsc.io/goversion/version"
)

包的匿名导入

import _ "pkg" 这种导入语句,最好只存在于main.go文件中

Dot 导入

package foo_test

import (
    . "foo"
)

不要在程序中使用 import .。它将使程序更难阅读

内联错误

不规范写法

// 查找返回键的值,如果没有键的映射,则返回空字符串。
func Lookup(key string) string

规范写法

// 查找并返回键的值,如果没有键的映射,则ok = false。
func Lookup(key string) (value string, ok bool)

并有利于写出更健壮和可读性更强的代码:

value, ok := Lookup(key)
if !ok {
    return fmt.Errorf("no value for %q", key)
}
return Parse(value)

缩进错误处理

要缩进错误处理逻辑,不要缩进常规代码。这样可以改进代码的可读性,读者可以快速地浏览逻辑主干。例如,不要写:

if x, err := f(); err != nil {
    // 错误处理
    return
} else {
    // 使用变量 x
}

相反,应该这样写:

x, err := f()
if err != nil {
    // 错误处理
    return
}
// 使用变量 x

这样写的好处可以增加可读性

首字母缩写

名称中的单词是首字母或首字母缩略词(例如 "URL" 或 "NATO" )需要具有相同的大小写规则。例如,"URL" 应显示为 "URL" 或 "url" (如 "urlPony" 或 "URLPony" ),而不是 "Url"。举个例子:ServeHTTP 不是 ServeHttp。对于具有多个初始化 “单词” 的标识符,也应当显示为 "xmlHTTPRequest" 或 "XMLHTTPRequest"。

当 "ID" 是 "identifier" 的缩写时,此规则也适用于 "ID" ,因此请写 "appID" 而不是 "appId"。

protocol buffer 生成的代码是个例外,对人和对机器的要求不能一样,人编写的代码要比机器编写的代码保持更高的标准。

接口

总的来说,Go 的接口要包含在使用方的包里,不应该包含在实现方的包里。实现方只需要返回具体类型(通常是指针或结构体),这样一来可以将新方法添加到实现中,而不需要扩展重构。

不要在 API 的实现者端定义 "for mocking" 接口;反而是要定义公开的 API,用真实的实现进行测试。

不要先定义接口再用它。脱离真实的使用场景,我们都不能确定一个接口是否有存在的价值,更别提设计接口的方法了

建议写法,把接口和接口具体的实现类分开两个go文件

package consumer  // consumer_func.go

type Thinger interface { Thing() bool }

func Foo(t Thinger) string { … }
package consumer //consumer.go

type defaultThinger struct{ … }
func (t defaultThinger) Thing() bool { … }

func NewThinger() Thinger { return defaultThinger{ … } }

不规范写法

package producer

type Thinger struct{ … }
func (t Thinger) Thing() bool { … }

func NewThinger() Thinger { return Thinger{ … } }

方法接收者命名

方法接收者的名称应该反映其身份;通常,其类型的一个或两个字母缩写就足够了(例如用 "c" 或 "cl" 表示 "client" )。不要使用通用名称,例如 "me","this" 或 "self",这是面向对象语言的典型标识符,这些标识符赋予该方法特殊的含义。

方法接收者类型

要是把握不准,就用指针。

变量名称

Go 中的变量名称尽可能短为妙,言简意赅,尤其是对于那些处于有限空间中的局部变量更是如此。例如: 用 c 而不是 lineCount; 用 i 而不是 sliceIndex

基本准则:当变量首次被使用时离声明的位置越远,变量名称必须更具描述性。对于方法接收者的名称来说,一个或者两个字母就足够了。普通变量比如 loop indicesreaders的名称用一个字母(i , r)指代就可以。

当然,对于一些逻辑比较复杂的逻辑,或者非常规事物,或者全局变量则需使用更具描述性的名字。


名称栏目:Go代码规范梳理
分享网址:http://ybzwz.com/article/dsoisjc.html