目录
1. 代码风格
1.1 代码格式
1.2 声明、初始化和定义
1.3 error 处理
1.4 panic处理" >1.4 panic处理
1.5 单元测试
2. 命名规范" >2. 命名规范
2.1 包命名规范" >2.1 包命名规范
2.2 文件命名规范
2.3 函数命名规范" >2.3 函数命名规范
2.4 结构体命名规范" >2.4 结构体命名规范
2.5 变量命名规范
2.6 常量命名规范
3. 类型
3.1 字符串
3.2 切片 slice
3.4 结构体 struct
4. 控制语句
4.1 if
4.2 for" >4.2 for
4.3 range
4.4 switch
4.5 goto
5. 函数
5.1 函数参数
首页 后端开发 Golang 分享一套Go编码规范!欢迎收藏!

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

Dec 09, 2022 pm 05:08 PM
golang 编码规范

最近在项目中也 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")
}
登录后复制
  • 业务代码中禁止抛出 panic 错误。
  • panic 只允许出现在在服务启动之前,如读取配置、链接存储(redis、mysql 等)。
  • 业务代码中建议用 error 而不是 panic 来传递。

1.5 单元测试

  • 每个重要的函数都要编写测试用例,合并代码要自动化运行一下所有的 test。
  • 文件命名 xxx_test.go。
  • 函数命名建议使用 Test函数名。

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

  • 包名必须与目录名一致(这和其他 php、Java 还是有一点不太一样的),尽量采取有意义、简短的包名,不要与 go 的标准库名称一样。
  • 包名小写,没有下划线,可以使用中划线隔开,使用多级目录来划分目录。
  • 包名不要出现复数命名。
  • 包名命名尽量简单一目了然,ge:user、log。

2.2 文件命名规范

  • 文件名要见名思义,尽量简而短
  • 文件名小写,组合词用下划线分割
  • 与 php、Java 一样,必须遵循驼峰规范,Go 语言中需要根据访问的控制决定大驼峰还是小驼峰。
  • 单元测试的函数用大驼峰,TestFunc。
  • 与 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}
登录后复制
  • 不允许在 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中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
4 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

如何使用 Golang 安全地读取和写入文件? 如何使用 Golang 安全地读取和写入文件? Jun 06, 2024 pm 05:14 PM

在Go中安全地读取和写入文件至关重要。指南包括:检查文件权限使用defer关闭文件验证文件路径使用上下文超时遵循这些准则可确保数据的安全性和应用程序的健壮性。

如何为 Golang 数据库连接配置连接池? 如何为 Golang 数据库连接配置连接池? Jun 06, 2024 am 11:21 AM

如何为Go数据库连接配置连接池?使用database/sql包中的DB类型创建数据库连接;设置MaxOpenConns以控制最大并发连接数;设置MaxIdleConns以设定最大空闲连接数;设置ConnMaxLifetime以控制连接的最大生命周期。

golang框架的优缺点比较 golang框架的优缺点比较 Jun 05, 2024 pm 09:32 PM

Go框架凭借高性能和并发性优势脱颖而出,但也存在一些缺点,如相对较新、开发者生态系统较小、缺少某些功能。此外,快速变化和学习曲线可能因框架而异。Gin框架以其高效路由、内置JSON支持和强大的错误处理而成为构建RESTfulAPI的热门选择。

Golang框架与Go框架:内部架构与外部特性对比 Golang框架与Go框架:内部架构与外部特性对比 Jun 06, 2024 pm 12:37 PM

GoLang框架与Go框架的区别体现在内部架构和外部特性上。GoLang框架基于Go标准库,扩展其功能,而Go框架由独立库组成,实现特定目的。GoLang框架更灵活,Go框架更容易上手。GoLang框架在性能上稍有优势,Go框架的可扩展性更高。案例:gin-gonic(Go框架)用于构建RESTAPI,而Echo(GoLang框架)用于构建Web应用程序。

Golang 框架中的错误处理最佳实践有哪些? Golang 框架中的错误处理最佳实践有哪些? Jun 05, 2024 pm 10:39 PM

最佳实践:使用明确定义的错误类型(errors包)创建自定义错误提供更多详细信息适当记录错误正确传播错误,避免隐藏或抑制根据需要包装错误以添加上下文

如何在 Golang 中将 JSON 数据保存到数据库中? 如何在 Golang 中将 JSON 数据保存到数据库中? Jun 06, 2024 am 11:24 AM

可以通过使用gjson库或json.Unmarshal函数将JSON数据保存到MySQL数据库中。gjson库提供了方便的方法来解析JSON字段,而json.Unmarshal函数需要一个目标类型指针来解组JSON数据。这两种方法都需要准备SQL语句和执行插入操作来将数据持久化到数据库中。

如何解决golang框架中常见的安全问题? 如何解决golang框架中常见的安全问题? Jun 05, 2024 pm 10:38 PM

如何在Go框架中解决常见的安全问题随着Go框架在Web开发中的广泛采用,确保其安全至关重要。以下是解决常见安全问题的实用指南,附带示例代码:1.SQL注入使用预编译语句或参数化查询来防止SQL注入攻击。例如:constquery="SELECT*FROMusersWHEREusername=?"stmt,err:=db.Prepare(query)iferr!=nil{//Handleerror}err=stmt.QueryR

如何找出 Golang 正则表达式匹配的第一个子字符串? 如何找出 Golang 正则表达式匹配的第一个子字符串? Jun 06, 2024 am 10:51 AM

FindStringSubmatch函数可找出正则表达式匹配的第一个子字符串:该函数返回包含匹配子字符串的切片,第一个元素为整个匹配字符串,后续元素为各个子字符串。代码示例:regexp.FindStringSubmatch(text,pattern)返回匹配子字符串的切片。实战案例:可用于匹配电子邮件地址中的域名,例如:email:="user@example.com",pattern:=@([^\s]+)$获取域名match[1]。

See all articles