用 Go 开发接口服务--Go 语言编码规范

栏目: Go · 发布时间: 4年前

内容简介:初学者使用 Go 语言开发项目的时候,首先需要熟悉一下该语言的编码规范,逐渐养成良好的编码习惯,提高自己的编码质量,对自己,对项目团队都受益匪浅。**【强制】程序内部命名方式**,一律采用驼峰命名方式。常量、变量、函数名都统一采用驼峰命名,公用对象首字母需大写,私有对象首字母可小写。有些特定名词或缩写名词,建议全部大写,如 HTML、XML、JSON、ID、UID、API、POST 等,但不是特定名词,请不要全部大写,包括常量和变量,避免全部大写,或者全部大写和下划线组合。正例:

初学者使用 Go 语言开发项目的时候,首先需要熟悉一下该语言的编码规范,逐渐养成良好的编码习惯,提高自己的编码质量,对自己,对项目团队都受益匪浅。

**【强制】程序内部命名方式**,一律采用驼峰命名方式。常量、变量、函数名都统一采用驼峰命名,公用对象首字母需大写,私有对象首字母可小写。有些特定名词或缩写名词,建议全部大写,如 HTML、XML、JSON、ID、UID、API、POST 等,但不是特定名词,请不要全部大写,包括常量和变量,避免全部大写,或者全部大写和下划线组合。

正例:

const (
    UserID           = 100001
    DefaultCharset  = "utf-8"
    ApplicationJSON = "application/json"
    TextHTML        = "text/html"
    TextXML         = "text/xml"
)

var (
	Expiration = 15 * time.Minute
)

func init() {
    ...
}

func MyProduct() {
    ...
}

反例:

// 以下都是不规范的命名
const (
    UserId           = 100001
    USERID           = 100001
    DefaultCharset  = "utf-8"
    ApplicationJson = "application/json"
    TextHtml        = "text/html"
    Text_Html       = "text/html"
    TEXTXML         = "text/xml"
    TEXT_XML        = "text/xml"
)

var (
	EXPIRATION = 15 * time.Minute
)

func INIT() {
    ...
}

func My_product() {
    ...
}

**【强制】项目名、包名、文件名命名不采用驼峰命名方式** ,项目名和包名优先采用小写名词命名方式,避免动词和下划线;文件名同理也优先采用小写名词命名方式,有时候可以适当采用下划线,尽量使用单数形式,避免复数名词。都规避采用 Go 关键字和预定的标识符。

正例:

// 项目名
project
// 包名
project/src/controller
project/src/model
project/src/util
// 文件名
article.go
article_test.go

反例:

// 项目名
Project
// 包名
Project/src/Controller
project/src/Models
project/src/utils
// 文件名
Article.go
ArticleTest.go

**【建议】多行方式导入包**,导入包分为: Go 标准包,第三方包,项目内部包,建议按照分类空一行分组导入包,包尽量按照字母排序。

正例:

import (
    "fmt"
    "time"
    
    "github.com/urfave/negroni"

    "project/src/common"
    "project/src/controller"
)

反例:

import "fmt"
import "time"
import "github.com/urfave/negroni"
import "project/src/common"
import "project/src/controller"

import (
    "fmt"
    "time"
    "github.com/urfave/negroni"
    "project/src/common"
    "project/src/controller"
)

**【强制】注释两种方式,可以两个斜杠 // 和 /* ... */**。// 之后应该有个空格,注释如果很长可以分多行,可以带逗号、句号等符号;/* *... */ 开始和结束分别占一行,中间是注释句子。一般双斜杠注释比较常见,代码首先是给人看的,所以配合一些必要的注释是良好的做法,但一些函数即使注释了也于事无补,要尽早重构。

正例:

// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// EOF is the error returned by Read when no more input is available.
// If the EOF occurs unexpectedly in a structured data stream,
// the appropriate error is either ErrUnexpectedEOF or some other error
// giving more detail.

/**
 * ErrShortWrite means that a write accepted fewer bytes than requested
 * but failed to return an explicit error.
 */

// Seek whence values.
const (
	SeekStart = 0 // seek relative to the origin of the file
)

反例:

//Copyright 2009 The Go Authors. All rights reserved.
//Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
//EOF is the error returned by Read when no more input is available.
// If the EOF occurs unexpectedly in a structured data stream,the appropriate error is either ErrUnexpectedEOF or some other error
//giving more detail.

/**ErrShortWrite means that a write accepted fewer bytes than requested
 * but failed to return an explicit error.*/

//Seek whence values.
const (
	SeekStart = 0//seek relative to the origin of the file
)

**【建议】函数注释开头写上函数的名称,再进行对函数注释。**

正例:

// SelectOneUser 获取一个用户记录
func SelectOneUser() (*model.User, error) {
    ...
}

反例:

//获取一个用户记录
func SelectOneUser() (*model.User, error) {
    ...
}

**【建议】一行代码长度不要超过120个字符,如果超过,请换行。**

**【建议】循环遍历,不要放在循环体内计算集合的长度。**

正例:

for i, s := 0, len(slice); i < s; i++ {
    ...
}

// 或另外外部定义
s := len(slice)
for i := 0; i < s; i++ {
    ...
}

反例:

for i := 0; i < len(slice); i++ {
    ...
}

**【建议】结构体初始化的时候,按照顺序标出属性名**

正例:

// BaseField 定义基类结构体
type BaseField struct {
	ID      int64
	Created time.Time
}

// BaseField 初始化
u := BaseField {
    ID      : 1,
    Created : time.Now(),
}

反例:

// BaseField 初始化
u := BaseField {1, time.Now()}
// BaseField 初始化
u := BaseField {
    1, 
    time.Now(),
}

**【建议】函数如果返回一个结构体实例,建议返回指针对象,因为指针可以是空指针,上层调用时可以进一步判断数据的完整性。**

正例:

func SelectOneUser() (*model.User, error) {
    ...
}

反例:

func SelectOneUser() (model.User, error) {
    ...
}

**【建议】空字符串判断,直接使用 ==,而不是 len 或 nil**

正例:

if name == "" {
    ...
}

反例:

if len(name) == 0 {
    ...
}

if s == nil || s == "" {
    ...
}

**【建议】空 slice 判断,直接使用 len,而不是  nil**

正例:

```go

if len(slc) > 0 {

...

}

```

反例:

```go

if slc != nil && len(slc) > 0 {

...

}

```

**【建议】布朗值判断,直接判断,而不是 ==**

正例:

```go

if b {

...

}

if !b {

...

}

```

反例:

```go

if b == true {

...

}

if b == false {

...

}

```

**【建议】缩短 if 判断语句,省略没必要的分支或代码**

正例:

```go

a, c := 1, 3

return a > c

if b {

return true

}

return false

```

反例:

```go

a, c := 1, 3

if a > c {

return true

} else {

return false

}

if b {

return true

} else {

return false

}

```

**【建议】append 两个 slice ,避免循环遍历**

正例:

```go

a := [1,3,5,7,9]

b := [2,4,6,8.10]

a = append(b, a...)

```

反例:

```go

a := [1,3,5,7,9]

b := [2,4,6,8.10]

for _,v := a {

append(b, v)

}

```

**【建议】涉及到 IO 文件流打开,数据库游标等操作,使用后一定记得 Close 关闭**

正例:

```go

// 打开 IO 文件流

file, err := os.Open("/path/file_name.txt")

if err != nil {

...

}

defer file.Close()

// 数据库游标操作

stmt, err := db.Prepare(`select * from user where status=?`)

if err != nil {

return err

}

defer stmt.Close()

rows, err := stmt.Query(1)

if err != nil {

return err

}

defer rows.Close()

```

反例:

```go

// 打开 IO 文件流

_, err := os.Open("/path/file_name.txt")

if err != nil {

...

}

// 数据库游标操作

stmt, err := db.Prepare(`select * from user where status=?`)

if err != nil {

return err

}

rows, err := stmt.Query(1)

if err != nil {

return err

}

```

**【建议】错误字符串不要大写,请全部小写,尽量说清楚错误特征,结尾不带结束符**

正例:

```go

file, err := os.Open("/path/file_name.txt")

if err != nil {

return errors.New("open file_name.txt fail")

}

...

```

反例:

```go

file, err := os.Open("/path/file_name.txt")

if err != nil {

return errors.New("Open file_name.txt Fail.")

// or

return err

}

...

```

**【建议】不要忽略 error ,在底层返回 error,在上层打印 error 日志**

正例:

```go

// 底层返回 error

var name string

_, err := stmt.QueryRow("select name from user where id=? limit 1",id).Scan(&name)

if err != nil {

return err

}

// 上层打印 error 日志

name, err := getUserName(id)

if err != nil {

log.Println(err)

}

```

反例:

```go

// 底层忽略了 error

var name string

stmt.QueryRow("select name from user where id=? limit 1",id).Scan(&name)

// 上层未打印 error 日志

name, _ := getUserName(id)

```

**【建议】方法接收器命名勿用 this、self  这些词,可以用结构体的缩写名,或首字母小写的全名**

正例:

```go

func (foo *Foo) sayHello() {

...

}

func (upf *UserProfile) sayHello() {

...

}

func (userProfile *UserProfile) sayHello() {

...

}

```

反例:

```go

func (this *Foo) sayHello() {

...

}

func (self *Foo) sayHello() {

...

}

```

**【建议】字符串和文件的处理,尽量使用 strings,io/ioutil 内置 工具 包的函数,减少造轮子**

**【建议】if 语句尽量避免多层嵌套,及时返回 **

正例:

```go

userId, err := selectUserId()

if err != nil {

return 0, err

if userId <= 0 {

return 0, errors.New("userId le zero")

}

return userId, nil

```

反例:

```go

userId, err := selectUserId()

if err == nil {

if userId > 0 {

return userId, nil

} else {

return 0, errors.New("userId le zero")

}

return 0, err

```

**小结**

Go 语言编码规范需尽早去学习,越早越好,否则开发项目之后,回头再看,自己肯定走了很多弯路。另外优秀的 IDE 工具有时候也会提示你按照规范去写,一边开发一边积累这些有用的规范。以上编码规范若有问题或有不详尽之处,请另行补充通知我。


以上所述就是小编给大家介绍的《用 Go 开发接口服务--Go 语言编码规范》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Beginning XML with DOM and Ajax

Beginning XML with DOM and Ajax

Sas Jacobs / Apress / 2006-06-05 / USD 39.99

Don't waste time on 1,000-page tomes full of syntax; this book is all you need to get ahead in XML development. Renowned web developer Sas Jacobs presents an essential guide to XML. Beginning XML with......一起来看看 《Beginning XML with DOM and Ajax》 这本书的介绍吧!

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换