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

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

内容简介:初学者使用 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 语言编码规范》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

PHP项目开发全程实录

PHP项目开发全程实录

清华大学出版社 / 2008 / 56.00元

《软件项目开发全程实录丛书•PHP项目开发全程实录:DVD17小时语音视频讲解(附光盘1张)》主要特色: (1)12-32小时全程语音同步视频讲解,目前市场上唯一的“全程语音视频教学”的案例类 图书,培训数千元容,尽在一盘中! (2)10套“应用系统”并公开全部“源代码”,誓将案例学习进行到底! (3)丛书总计80个应用系统300个应用模块。 (4)含5000页SQL se......一起来看看 《PHP项目开发全程实录》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

MD5 加密
MD5 加密

MD5 加密工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器