用 Go 开发终端接口服务--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) { ... }
**【建议】循环遍历,不要放在循环体内计算集合的长度。**
正例:
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**
正例:
if len(slc) > 0 { ... }
反例:
if slc != nil && len(slc) > 0 { ... }
**【建议】布朗值判断,直接判断,而不是 ==**
正例:
if b { ... } if !b { ... }
反例
if b == true { ... } if b == false { ... }
**【建议】缩短 if 判断语句,省略没必要的分支或代码**
正例:
a, c := 1, 3 return a > c if b { return true } return false
反例:
a, c := 1, 3 if a > c { return true } else { return false } if b { return true } else { return false }
**【建议】append 两个 slice ,避免循环遍历**
正例:
a := [1,3,5,7,9] b := [2,4,6,8.10] a = append(b, a...)
反例:
a := [1,3,5,7,9] b := [2,4,6,8.10] for _,v := a { append(b, v) }
**【建议】涉及到 IO 文件流打开,数据库游标等操作,使用后一定记得 Close 关闭**
正例:
// 打开 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()
反例:
// 打开 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 }
**【建议】错误字符串不要大写,请全部小写,尽量说清楚错误特征,结尾不带结束符**
正例:
file, err := os.Open("/path/file_name.txt") if err != nil { return errors.New("open file_name.txt fail") } ...
反例:
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 日志**
正例:
// 底层返回 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) }
反例:
// 底层忽略了 error var name string stmt.QueryRow("select name from user where id=? limit 1",id).Scan(&name) // 上层未打印 error 日志 name, _ := getUserName(id)
**【建议】方法接收器命名勿用 this、self 这些词,可以用结构体的缩写名,或首字母小写的全名**
正例:
func (foo *Foo) sayHello() { ... } func (upf *UserProfile) sayHello() { ... } func (userProfile *UserProfile) sayHello() { ... }
反例:
func (this *Foo) sayHello() { ... } func (self *Foo) sayHello() { ... }
**【建议】字符串和文件的处理,尽量使用 strings,io/ioutil 内置工具包的函数,减少造轮子**
**【建议】if 语句尽量避免多层嵌套,及时返回 **
正例:
userId, err := selectUserId() if err != nil { return 0, err } if userId <= 0 { return 0, errors.New("userId le zero") } return userId, nil
反例:
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 语言基本语法
- Go 语言编码规范
- 快速编写一个 Web 服务器
- 项目整体结构介绍
- 准备项目所需的 Go 类包
- 公共类关键函数
- 定义 model 实体层结构体
- 灵活写 dao 数据层函数
- 按需写 service 服务层逻辑
- 暴露 controller 控制层接口
- 测试已写好的接口
- 把项目部署到服务器
- 保证高性能项目的法宝
- 写在后面
1 楼: 噜啦 发表于 2021-11-22 20:54:43 回复 TA