ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
# GO语言代码规范说明 **《计算机程序设计与解释》** 中曾经指出“ 代码必须是本着给人阅读的原则来编写,同时顺便给计算机执行而已”,这句话简单精炼的概括出了代码风格的作用。当你阅读风格混乱的代码的时候,你会深深的赞同上面的观点的。 代码风格是一个与人有关而计算机无关的问题。代码风格的好坏,并不会影响计编译器的编译执行,但是它确实会影响到团队工作的协同开发、影响代码的复用、功能的升级演化、代码BUG的修复。 每个语言都有属于自己的代码规范,在我们学习和使用任何一门编程语言的时候都必须遵循它的代码规范,只有在遵循代码规范的基础进行编码,才能写出通用优雅的代码。 GO语言可能是唯一一个将代码规范强制统一的语言。其他编译器完全忽略的问题,在GO语言的编辑器前会被认为是编译错误。因此我们在学习和使用GO语言的时候必须严格按照GO语言的代码规范进行编码。 GO语言的编码规范主要分为两大类,分别是GO编译器进行的强制编码规范以及由GO语言推行的非强制性编码风格建议。 **强制性编码规范** GO编译器强制的编码规范也是GO语言设计者认为最需要统一的代码风格,下面我们来加一简单的说明。 1. 命名 GO语言从语法层面进行了以下限定:任何需要对完暴露的名字必须是大写字目开头,不需要对完暴露的则应该以小写字母开头。 软件开发行业最常见的两种命名方法:驼峰命名法(例如 UserInfo 和 userInfo)和下划线命名法(例如 user_info),而GO语言明确宣告了用户驼峰命名法而排斥下划线命名法。骆驼命名法在Java和C#中得到官方的支持和推荐,而下划线命名法则主要用在C语言的世界里,比如Linux内核和驱动开发,php则是驼峰法和下划线命名法都是支持,而且现在有的php框架开始更多的推广全小写字母+下划线命名法。在我们学习和使用GO语言开发的过程还是彻底忘记下划线命名法吧,避免写出不伦不类的名字。 2. 排列 GO语言甚至对代码的排列方式也进行了语法级别的检查,约定了代码块中花括号的明确摆放位置。 Go语言要求“{”必须放在代码最后一行,不得单独占一行;同时,else甚至都必须紧跟在之前的右花括号”}“后面并且不能换行。 Go语言的这条规则基本上就保证了所有Go代码的逻辑结构写法是完全一致的,也不会再出现有洁癖的程序员在维护别人代码之前非要把所有花括号的位置都调整一遍的问题。 **非强制性编码风格建议** 在程序编译可以的通过的情况下,可以适当调整对代码进行调整来提升代码的可读性。主要内容包括: * 调整了每条语句的位置 * 重新摆放花括号的位置 * 以制表符缩进代码 * 添加空格 当然,对于程序编码风格是可以通过go fmt 工具来完成的。Go语言提供了一个强大的编码风格调整工具,在程序可以通过编译后,可以运行:go fmt xxx.go 命令来完成对于源代码文件xxx.go的编码风格调整,调整后的代码就完全符合以上的风格建议,当然,对于命名规则就无法完成调整了,不过源代码在调整后就更具有可读性。 # Go语言代码规范指导 下面根据GO语言的官方规范,整理下相关的规范指导,方便团队形成统一的代码风格,提高代码的可读性、规范性、统一性。本规范从命名规范、注释规范、代码风格、GO语言提供的工具这几个方面做一个简单的说明。 ## 一、命名规范 命名是代码规范中非常重要的一部分,统一的命名规范有利于提高代码的可读性,好的命名规范,仅仅通过命名就可以获取足够多的信息。 Go在命名时以字母a到Z或a到Z或下划线开头,后面跟着零或更多的字母、下划线和数字(0到9)。Go不允许在命名时中使用@、$和%等标点符号。Go是一种区分大小写的编程语言。因此,Manpower和manpower是两个不同的命名。 1. 当命名(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:Group1,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为导出(像面向对象语言中的 public); 2. 命名如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(像面向对象语言中的 private ) ### 1、包命名:package 包命名保持和目录的命名一致,尽量采取简短、有意义的命名 并且主要尽量不要和标准库的命名冲突。包名为小写字母,不要带下划线。 ``` package demo package main ``` 2、文件名莫名 尽量采取有意义的文件名,简短,小写单词,文件命名是可以是下划线分隔单词。 ``` my_test.go ``` 3、结构体命名 * 采用驼峰命名法,首字母根据访问控制大小写 * struct 声明和初始化格式采用多行 ``` //多行声明 type User struct{ Username string Email string } u :User{ Username:'xiaoming', Email:'xiaoming@mail.com', } ``` 4、接口命名 * 命名规则基本和上面的结构体类似 * 单个函数的结构名以“er”作为后缀,例如 Reader , Writer. ``` type Reader interface{ Read(p []byte) (n int, err error) } ``` 5、变量命名 * 和结构类似,变量名称一般遵循驼峰法,首字母根据访问规则控制大写或者小写,但遇到特有名词时,需要遵循以下原则: * 如果变量为私有,且特有名词为首个单词,则使用小写 如apiClient * 其他情况应当使用名词原有的写法 如 APIClient 、repoID 、UserId * 错误示例: UrlArray ,应该写成 urlArray 或者 URLArray * 如变量类型 bool 类型 ,则名称以 Has 、Is 、Can 、Allow 开头 ``` var isExist bool var hasConflict bool var canMange bool var allowGitHook bool ``` 6、常量命名 常量均使用全部大写字母,使用下划线分词 ``` const APP_VERSION = "1.0" ``` 如果是枚举类型的常量,则需要先创建相应的类型 ``` type Scheme string const { HTTP Scheme = "http" HTTPS Scheme = "https" } ``` 7、关键字 下面列表显示了GO语言保留的保留单词,这些保留单词不能用做常量、变量、其他的标识符名称 | break | default | func | interface | select | case | | --- | --- | --- | --- | --- | --- | | **defer** | **Go** | **map** | **Struct** | **chan** | **else** | | **Goto** | **package** | **Switch** | **const** | **fallthrough** | **if** | | **if** | **range** | **Type** | **continue** | **for** | **import** | | **return** | **Var** | | | | | ## 二、注释 不管是那种开发语言,在开发过程注释对于团队协作开发、后期BUG的修改、功能的优化等等都是特别重要的。 编程语言中的java、php、go、python的注释风格都跟C语言的注释风格比较接近。比如 /**/ 这种块注释是来自C,// 行注释是C++的风格。行注释用的表较多,属于常态注释;块注释主要为文件注释或者包注释,但是在开发过程也是比较常用的,尤其是表达式中很有用或者禁用大量代码的都会用到块注释。 * 单行注释是最常见的注释方式,可以在任何地方使用以 //开头的单行注释。 * 块注释是以 /* 开头 ,并以 */ 结尾的 不可以嵌套使用,多行注释一般用于包的文档注释或者代码片段的注释。 go 语言自带的 godoc 工具可以根据注释生成文档,生成可以自动生成对应的网站( [http://golang.org](https://link.zhihu.com/?target=http%3A//golang.org)就是使用 godoc 工具直接生成的),注释的质量决定了生成的文档的质量。每个包都应该有一个包注释,在package子句之前有一个块注释。对于多文件包,包注释只需要存在于一个文件中,任何一个都可以。包评论应该介绍包,并提供与整个包相关的信息。它将首先出现在`godoc`页面上,并应设置下面的详细文档。 详细的如何写注释可以 参考:[http://golang.org/doc/effective\_go.html#commentary](https://link.zhihu.com/?target=http%3A//golang.org/doc/effective_go.html%23commentary) ### 1、包注释 每个包都应该有一个包注释,一个位于package语句之前的块注释或者行注释,包如果有多个go文件,只需要在其中一个go文件中加注释即可。包注释一般按照下面基本信息创建,当然有的公司开发团队会有自己的注释风格,如果公司团队没有要求,建议使用下面的方式去标注注释: * 包的基本简介(包名、简介) * 创建者, 格式:创建人:xx * 创建时间,格式:创建时间:xxxxx 例如 util 包注释示例如下 ``` /* utile 包 ,该包包含了项目公用的一些常量,封装了项目中一些公用函数 创建人:帝君 创建时间:20200522 */ ``` ### 2、结构(接口)注释 每个自定义的结构或者接口都应该有注释说明,该注释对结构或者接口进行简要的介绍,放在结构体定义的前一行,格式为:结构体名、结构体说明。同时结构体内的每个成员变量都要说明,该说明放在成员变量的后面(注意跟变量对齐),实例如下: ``` // User , 用户对象定义用户的基础信息 type User struct{ Username string //用户名 Email string // 用户邮箱 } ``` ###3、函数(方法)注释 每个函数或者方法(结构体或者接口下的函数统称为方法)都应该有注释说明,函数的注释应该包括三个方面 * 简要说明,格式说明:以函数名开头 “,” 分隔说明部分 * 参数列表,格式说明:每行一个参数 参数名开头“,” 分隔说明部分 * 返回值:每行一个返回值 示例如下 ``` // NewtAttrModel , 属性数据层操作类的工厂方法 //参数 ctx , 上下文信息 // 返回值: 属性操作指针 func NewAttrModel(ctx *common.Content) *AttrModel{ } ``` ### 4、代码逻辑注释 对于一些关键位置的代码逻辑,或者一些逻辑比较复杂的逻辑,需要相应的逻辑说明,方便其他开发这阅读该段代码示例如下: ``` // 从 redis 读取数据,没有读取的 ID 没记录到一个数组里面,准备从数据库中读取 xxxxxxxx xxxxxxxx xxxxxxxx ``` ###5、注释风格 统一使用中文注释,对于中英文之间严格使用空格分隔,这个不仅仅是中文和英文之间,英文和中文之间标点也都要使用空格分隔,例如 ``` // 从 redis 读取数据,没有读取的 ID 没记录到一个数组里面,准备从数据库中读取 ``` ## 三、代码风格 ### 1、缩进和折行 * 缩进直接使用 gofmt 工具格式化即可(gofmt 是使用 tab 缩进的); * 折行方面,一行最长不超过120个字符,超过的请使用换行展示,尽量保持格式优雅。 我们使用Goland开发工具,可以直接使用快捷键:ctrl+alt+L,即可。 ### 2、语句的结尾 Go语言中是不需要类似于Java需要冒号结尾,默认一行就是一条数据 如果你打算将多个语句写在同一行,它们则必须使用 ; ### 3、括号和空格 括号和空格方面,也可以直接使用 gofmt 工具格式化(go 会强制左大括号不换行,换行会报语法错误),所有的运算符和操作数之间要留空格。 ``` //正确的方式 if a > 0 { } //错误的方式 if a>0 // a、0、> 之间应该有空格 { //左大括号不能换行不然会报语法错误 } ``` ### 4、import 规范 import在多行的情况下,goimports会自动帮你格式化,但是我们这里还是规范一下import的一些规范,如果你在一个文件里面引入了一个package,还是建议采用如下格式: ``` import( "fmt" ) ``` 如果你的包引入了三种类型的包,标准库包,程序内部包,第三方包,建议采用如下方式进行组织你的包: ``` import( "encodeing/jsong" "stryings" "myproject/models" "myproject/controller" "myproject/utils" "github.com/astaxie/beego" "github.com/go-sql-deiver/mysql" ) ``` 有顺序的引入包,不同的类型采用空格分离,第一种实标准库,第二是项目包,第三是第三方包。 在项目中不要使用相对路径引入包: //错误的包导入 ``` import "../net" //正确的导入 import "github.com/repo/proj/src/net" ``` 但是如果是引入本项目中的其他包,最好使用相对路径。 ### 5、错误处理 * 错误处理的原则就是不能丢弃任何有返回err的调用,不要使用 \_ 丢弃,必须全部处理。接收到错误,要么返回err,或者使用log记录下来 * 尽早return:一旦有错误发生,马上返回 * 尽量不要使用panic,除非你知道你在做什么 * 错误描述如果是英文必须为小写,不需要标点结尾 * 采用独立的错误流进行处理 ``` //错误的写法 if err != nil { //error handliing } else { // normal code } //正确的写法 if err != nil { // error handliing return //or continue ,etc } //normal code ```