热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

分享一套Go编码规范!欢迎收藏!

最近在项目中也codereview了不少Go语言的代码,有必要总结下代码规范,算是一个笔记记录了。说在前面,这只是我们团队的一套规范而已。今天我们聊一下Go的编码规范,大概分为几大

最近在项目中也 codereview 了不少 Go 语言的代码,有必要总结下代码规范,算是一个笔记记录了。


说在前面,这只是我们团队的一套规范而已。


今天我们聊一下 Go 的编码规范,大概分为几大模块,如注包/变量/常量命名、基本语法、函数、错误处理、心得等。【推荐:golang教程】


1. 代码风格


1.1 代码格式



  • 代码必须用 gofmt 进行格式化,goland 可以配置,可以自行搜索一下配置

  • 我们编写的代码每行应该不超过 120 个字符,超出部分用换行解决。

  • 单个文件最大行数最大不超过 800 行.

  • 单个函数最大行数不超过 80 行。

  • import 规范

    • 不要使用相对路径引入包,例如 import ../util/net

    • 在导入包时,多个相同包名冲突时,必须使用导入别名



// bad
"github.com/google/uuid"
// good
uuid "github.com/google/uuid"



  • 导入的包建议分组,引用匿名包建议用一个新的分组,并加上注释方便后面小伙伴阅读

import (
// Go 标准库
"fmt"
//第三方包
"github.com/jinzhu/gorm"
"github.com/google/uuid"
"github.com/go-redis/redis/v8"
// 匿名包
/import mysql driver
_"github.com/jinzhu/gorm/dialects/mysql"
// 内部包
slice "xxx.local/pkg/v1/goslice"
meta "xxx.local/pkg/v1/meta"
gomap "xxx.local/pkg/v2/gomap")


1.2 声明、初始化和定义



  • 一个函数需要使用多个变量时,可以在函数最开头处使用 var 声明。在函数外部声明的变量不能使用 :=,会踩坑,不知道的可以评论区留言(要评论不易呀)!

var (
port = 8081
metricServerPort = 2001)



  • 在初始化结构体用 &struct 代替 new(struct),确保与结构体初始化一致,初始化结构体时换行。

// bad
stu := new(S)
stu.Name = "张三"
// good
stu := &S{
Name:"李四"
}



  • 使用 make 在声明 map、array 等应该指定容器的容量,从而达到预先分配内容。

users := make(map[int]string, 10)tags := make([]int, 0, 10)



  • 使用标准 var 关键字事,不要指定类型,除非它与表达式的类型不同。

// bad
var _f string F()
func F() string {
return "hello world!"
}
// good
var _f F()
func F() string {
return "hello world!"
}


1.3 error 处理



  • 若函数返回 error, 必须对 error 进行处理,如果业务允许可以用 _ 接受忽略。对应 defer 可以不用显式进行处理。

// bad
func InitConfig() error {
...
}
InitConfig()
// good
func InitConfig() error {
...
}
err := InitConfig()
if err != nil {
...
}
// or
_ := InitConfig()



  • error 作为返回值时必须作为最后一个参数返回

// bad
func InitConfig() (error,int) {
...
}
// good
func InitConfig() (int, error) {
...
}



  • 错误需要单独处理,尽量不要与其他的逻辑耦合在一起。

// bad
res, err := InitConfig()
if err != nil || res != nil {
return err
}
// good
res, err := InitConfig()
if err != nil {
return err
}
if res != nil {
return fmt.Errorf("invalid result")
}


1.4 panic处理



  • 业务代码中禁止抛出 panic 错误。

  • panic 只允许出现在在服务启动之前,如读取配置、链接存储(redis、mysql 等)。

  • 业务代码中建议用 error 而不是 panic 来传递。


1.5 单元测试



  • 每个重要的函数都要编写测试用例,合并代码要自动化运行一下所有的 test。

  • 文件命名 xxx_test.go。

  • 函数命名建议使用 Test函数名。


2. 命名规范

在每个语言中,命名规范在代码规范中非常重要,一个统一的、精确的命名不仅仅可以提高代码的可读性,也可以让人觉的这个同志真的会呀。牛!


2.1 包命名规范



  • 包名必须与目录名一致(这和其他 php、Java 还是有一点不太一样的),尽量采取有意义、简短的包名,不要与 go 的标准库名称一样。

  • 包名小写,没有下划线,可以使用中划线隔开,使用多级目录来划分目录。

  • 包名不要出现复数命名。

  • 包名命名尽量简单一目了然,ge:user、log。


2.2 文件命名规范



  • 文件名要见名思义,尽量简而短

  • 文件名小写,组合词用下划线分割


2.3 函数命名规范



  • 与 php、Java 一样,必须遵循驼峰规范,Go 语言中需要根据访问的控制决定大驼峰还是小驼峰。

  • 单元测试的函数用大驼峰,TestFunc。


2.4 结构体命名规范



  • 与 php、Java 一样,必须遵循驼峰规范,Go 语言中需要根据访问的控制决定大驼峰还是小驼峰。

  • 避免使用 info 、data 这种无意义的名称。

  • 命名使用名词而非动词。

  • 结构体在声明和初始化的时候需要换行,eg:

type Student struct{
Name string
Age uint8}student := Student{
Name: "张三",
Age: 18,}


2.5 变量命名规范



  • 和 php、Java 一样,必须遵循驼峰规范,Go 语言中需要根据访问的控制决定大驼峰还是小驼峰。

  • 若变量为私有时,可以使用小写命名。

  • 局部变量可以简写,eg:i 表示 index。

  • 若变量代表 bool 值,则可以使用 Is 、Can、Has 前缀命名,eg:

var isExit boolvar canReturn bool


2.6 常量命名规范



  • 必须遵循驼峰规范,Go 语言中需要根据访问的控制决定大驼峰还是小驼峰。

  • 若代表枚举值,需要先创建。

type Code intconst (
ErrNotFound Code = iota
ErrFatal)


3. 类型


3.1 字符串

好像学过的语言中,都是从字符串开始说起的。就像写代码第一行都是从 Hello World!一样!同意的点赞哈。



  • 字符串判空值

// bad
if s == "" {
...}
// good
if len(s) == 0 {
...}



  • 字符串去除前后子串。

// bad
var s1 "hello world"var s2 "hello"var s3 strings.TrimPrefix(s1, s2)
// good
var s1 "hello world"var s2 "hello"var s3 stringif strings.HasPrefix(s1, s2){
s3 = s1[len(s2):]}


3.2 切片 slice



  • 声明 slice。

// bad
s := []string{}s := make([]string, 10)
// good
var s []string
s := make([]string, 0, 10)



  • 非空判断。

//bad
if len(slice) >0 {
...}
// good
if slice != nil && len(slice) > 0 {
...}



  • slice copy。

// badvar b1,b2 []bytefor i, v := range b1 {
b2[i] = v}for i := range b1 {
b2[i] = b1[i]}// goodcopy(b2,b1)



  • slice 新增。

// bad
var a,b []intfor _, v := range a {
b = append(b,v)}
// good
var a, b []int
b := append(b, a...)


3.4 结构体 struct



  • 初始化需要多行。

type Student struct{
Name string
Age uint8}student := Student{
Name: "张三",
Age: 18,}


4. 控制语句


4.1 if



  • if 可以用局部变量的方式初始化。

if err := InitConfig; err != nil {
return err}


4.2 for



  • 不允许在 for 中使用 defer, defer 只在函数结束时才会执行。

// bad
for file := range files {
fd, err := os.Open(file)
if err != nil {
return err }
defer fd.close()}
// good
for file := range files{
func() {
fd,err := os.open(file)
if err!=nil {
return err }
defer fd.close()
}()}


4.3 range



  • 如果不需要 key 直接用 _ 忽略,value 也一样。

for _, v := range students {
...}for i, _ := range students {
...}for i, v := range students {
...}

注: 若操作指针时请注意不能直接用 s := v。想知道可以评论区告诉我哦!


4.4 switch



  • 和其他语言不一样,必须要有 defalt

switch type {
case 1:
fmt.Println("type = 1")
break
case 2:
fmt.Println("type = 2")
break
default :
fmt.Println("unKnown type")}


4.5 goto



  • 业务中不允许使用 goto。

  • 框架和公共工具也不允许使用 goto。


5. 函数



  • 传参和返回的变量小写字母。

  • 传入参数时slice、map、interface、chan 禁止传递指针类型。

  • 采用值传递,不用指针传值。

  • 入参个数不能超出 5 个,超过的可以用 struct 传值。


5.1 函数参数



  • 返回值超出 1 个时,需要用变量名返回。

  • 多个返回值可以用 struct 传。


5.2 defer



  • 当操作资源、或者事物需要提交回滚时,可以在创建开始下方就使用 defer 释放资源。

  • 创建资源后判断 error,非 error 情况后在用 defer 释放。


5.3 代码嵌套



  • 为了代码可读性,为了世界和平,尽量别用太多的嵌套,因为真的很难有人类能看懂。


6. 日常使用感悟



  • 能不用全局变量就不用,可以用参数传值的方式,这样可以大大降低耦合,更有利于单元测试。

  • 衣服开发中,在函数间多用 context 传递上下文,在请求开始时可以生成一个 request_id,便于链路、日志追踪。


6.1 提高性能



  • 在业务开发中,尽量使用 strconv 来替代 fmt。

  • 我们在使用 string 字符串类型时,当修改的场景较多,尽量在使用时用 []byte 来替代。因为每次对 string 的修改都需要重新在申请内存。


6.2 避免踩坑



  • append 要小心自动扩容的情况,最好在申明时分配好容量,避免扩容所带来的性能上的损耗以及分配新的内存地址。若不能确定容量,应选择一个比较大一点的值。

  • 并发场景下,map 非线程安全,需要加锁。还有一种评论区告诉我吧。

  • interface 在编译期间无法被检查,使用上会出现 panic,需要注意


7. 总结

本篇很讲了 Go 语言的编码规范,当时想说的,规范是大家预定的东西,每个公司、团队都会有不一样的规范,只要大家一起遵循就好啦。你可以根据自己团队的需求,定一套属于自己团队的项目规范。如果想小伙伴一起遵循,可以借助一些工具来保障执行度。

讲了很多,虽然很基础,希望对于刚刚转 Go 语言,或者刚学习 Go 语言的同学有帮助吧。今天就到这里了。希望得到大家的一键三连。感谢!


本文系转载,原文链接:mp.weixin.qq.com/s/lfjP9DEia2WL4Ua...


以上就是分享一套Go编码规范!欢迎收藏!的详细内容,更多请关注北冥有鱼其它相关文章!

本文转载自【PHP中文网】,希望能给您带来帮助,苟日新、日日新、又日新,生命不息,学习不止。



推荐阅读
  • (一)javax.mail.Session:Session类代表JavaMail中的一次邮件会话.每个基于JavaMail的应用程序至少有一次会话,也可以产生多次会话.发送邮件之前 ... [详细]
  • 最近自己做一个工具最后涉及到一个存储成bmp位图的形式,由于这部分并不是整个project的重点我就从网上找了例子改了改,但是目前的问题是有很多时候都是存储的bmp全黑,我也并不知道是怎么回事。 ... [详细]
  • Mysql MySqlBulkLoader在.NET平台下的批量插入
    批量导入publicboolTranBatchImpo ... [详细]
  • FluxCD、ArgoCD或Jenkins X,哪个才是适合你的GitOps工具?
    GitOps是一种使用基于Git的工作流程来全面管理应用和基础设施的想法,其在最近获得了极大关注。新一代的部署工具更能说明这一点,它们将GitOps作为 ... [详细]
  • 遇到的问题golang对于基本类型初始化的处理,是自动给基本类型赋值为默认值。比如:variint在这里如果不对i做任何赋值,那么i的值为零这个特性在很多地方能够避免访问到未初始化 ... [详细]
  • IPVlan 详解
    文章目录简介Ipvlan2同节点Ns互通Ns内与宿主机通信第三种方法Ns到节点外部结论Ipvlan31.同节点Ns互通Ns内与宿主机通信Ns内到外部网络总结源码分析ipvlan收包 ... [详细]
  • 1、概念共享内存:共享内存是进程间通信中最简单的方式之一。共享内存允许两个或更多进程访问同一块内存,就如同malloc()函数向不同进程返回了指向同一个 ... [详细]
  • Logistic回归主要针对输入的数据是多个,输出则是有限的数值型,多为2个分类。涉及到以下方面:1.输出yw0+w1*x1+w2*x2+..(x1,x2,是样本的 ... [详细]
  • 稀松数组
    稀松数组1.稀松数组什么?在一个数组中,若数值为0的元素数目远远多于非0元素的数目,并且非0元素分布没有规律时,则称该数组为稀疏数组;如图,一个5*5的数组arr上只有3个有效数值 ... [详细]
  • Java发布webservice应用并发送SOAP请求调用
    webservice框架有很多,比如axis、axis2、cxf、xFire等等,做服务端和做客户端都可行,个人感觉使用这些框架的好处是减少了对于接口信息的解析,最主要的是减少了对于传递于网络中XML ... [详细]
  • 下面是一个用openssl实现获取https网页内容的demo,整个流程比较简单,主要封装的API如下staticinthttps_init(http ... [详细]
  • Ithinkthishasbeenupbefore,butcouldntfindanyanswertoit.Ifitsalreadyansweredplease ... [详细]
  • 编译linux搭建vs2015,使用Vs2015开发linux(centos7)程序
    1.首先下载vs2015withupdate32.然后下载VisualCforLinuxDevelopment3.在centos7上yuminstallopenssh-server ... [详细]
  • 是的,可以在RDSMySqlEngine中进行Master-Master复制。但它需要一些操作与实例。先决条件:1)为启用二进制日志记录创建两个实例的只 ... [详细]
  • 使用gin改写“SectionBuildingRESTfulAPIs”第三方包需要提前准备的包有:“gopkg.ingin-gonicgin.v1”“gopkg.inmgo.v2” ... [详细]
author-avatar
mobiledu2502884717
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有