Share a set of Go coding standards! Welcome to collect!

藏色散人
Release: 2022-12-09 17:10:05
forward
5603 people have browsed it

Recently, I have codereviewed a lot of Go language code in the project. It is necessary to summarize the code specifications, which can be regarded as a note record.

As mentioned earlier, this is just a set of norms for our team.

Today we talk about Go’s coding standards, which are roughly divided into several major modules, such as package injection/variable/constant naming, basic syntax, functions, error handling, experience, etc. [Recommended: golang tutorial]

1. Code style

1.1 Code format

  • The code must be formatted with gofmt, goland can Configuration, you can search for the configuration by yourself
  • Each line of the code we write should not exceed 120 characters, and the excess part should be solved by line breaks.
  • The maximum number of lines in a single file does not exceed 800 lines.
  • The maximum number of lines in a single function does not exceed 80 lines.
  • Import specifications
    • Do not use relative paths to introduce packages, for example import ../util/net
    • When importing packages, multiple identical packages When there is a name conflict, you must use the imported alias
// bad
"github.com/google/uuid"

// good
uuid "github.com/google/uuid"
Copy after login
  • . The imported package is recommended to be grouped. It is recommended to use a new group when referencing the anonymous package, and add comments for convenience. Partner Reading
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")
Copy after login

1.2 Declaration, Initialization and Definition

  • When a function needs to use multiple variables, you can use the var declaration at the beginning of the function. Variables declared outside the function cannot use :=, which may lead to pitfalls. If you don’t know, you can leave a message in the comment area (it’s not easy to comment)!
var (
    port = 8081
    metricServerPort = 2001)
Copy after login
  • Use &struct instead of new(struct) when initializing the structure to ensure that it is consistent with the initialization of the structure and wrap the line when initializing the structure.
// bad
stu := new(S)
stu.Name = "张三"

// good
stu := &S{
    Name:"李四"
}
Copy after login
  • Using make, you should specify the capacity of the container when declaring map, array, etc., so as to pre-allocate the content.
users := make(map[int]string, 10)tags := make([]int, 0, 10)
Copy after login
  • Use the standard var keyword thing and do not specify a type unless it is different from the type of the expression.
// bad
var _f string F()

func F() string {
    return "hello world!"
}

// good 
var _f F()

func F() string {
    return "hello world!"
}
Copy after login

1.3 Error processing

  • If the function returns an error, the error must be processed. If the business allows, you can use _ to accept and ignore it. Corresponding defer can be processed without explicit processing.
// bad
func InitConfig() error {
    ...
}
InitConfig()


// good
func InitConfig() error {
    ...
}
err := InitConfig()
if err != nil {
    ...
}
// or 
_ := InitConfig()
Copy after login
  • error must be returned as the last parameter when used as a return value
// bad
func InitConfig() (error,int) {
    ...
}

// good 
func InitConfig() (int, error) {
    ...
}
Copy after login
  • Errors need to be handled separately and try not to be coupled with other logic. Together.
// 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")
}
Copy after login

1.4 Panic handling

  • It is forbidden to throw panic errors in business code.
  • panic is only allowed to appear before the service is started, such as reading configuration, link storage (redis, mysql, etc.).
  • It is recommended to use error instead of panic in business code.

1.5 Unit Test

  • A test case must be written for each important function, and all tests must be automatically run when merging the code.
  • The file is named xxx_test.go.
  • It is recommended to use the Test function name for function naming.

2. Naming convention

In every language, naming convention is very important in code specification. A unified and accurate naming can not only Improving the readability of the code can also make people feel that this comrade really knows how to do it. ox!

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,}
Copy after login
Copy after login

2.5 变量命名规范

  • 和 php、Java 一样,必须遵循驼峰规范,Go 语言中需要根据访问的控制决定大驼峰还是小驼峰。
  • 若变量为私有时,可以使用小写命名。
  • 局部变量可以简写,eg:i 表示 index。
  • 若变量代表 bool 值,则可以使用 Is 、Can、Has 前缀命名,eg:
var isExit boolvar canReturn bool
Copy after login

2.6 常量命名规范

  • 必须遵循驼峰规范,Go 语言中需要根据访问的控制决定大驼峰还是小驼峰。
  • 若代表枚举值,需要先创建。
type Code intconst (
    ErrNotFound Code = iota
    ErrFatal)
Copy after login

3. 类型

3.1 字符串

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

  • 字符串判空值
// bad
if s == "" {
    ...}
 // good
 if len(s) == 0 {
    ...}
Copy after login
  • 字符串去除前后子串。
// 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):]}
Copy after login

3.2 切片 slice

  • 声明 slice。
// bad
s := []string{}s := make([]string, 10)
// good
var s []string
s := make([]string, 0, 10)
Copy after login
  • 非空判断。
//bad
if len(slice) >0 {
    ...}
 // good
 if slice != nil && len(slice) > 0 {
    ...}
Copy after login
  • slice copy。
// badvar b1,b2 []bytefor i, v := range b1 {
    b2[i] = v}for i := range b1 {
    b2[i] = b1[i]}// goodcopy(b2,b1)
Copy after login
  • slice 新增。
// bad
var a,b []intfor _, v := range a {
    b = append(b,v)}
// good
var a, b []int
b := append(b, a...)
Copy after login

3.4 结构体 struct

  • 初始化需要多行。
type Student struct{
    Name string
    Age uint8}student := Student{
    Name: "张三",
    Age: 18,}
Copy after login
Copy after login

4. 控制语句

4.1 if

  • if 可以用局部变量的方式初始化。
if err := InitConfig; err != nil {
    return err}
Copy after login

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()
    }()}
Copy after login

4.3 range

  • 如果不需要 key 直接用 _ 忽略,value 也一样。
for _, v := range students {
    ...}for i, _ := range students {
    ...}for i, v := range students {
    ...}
Copy after login

注: 若操作指针时请注意不能直接用 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")}
Copy after login

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...

The above is the detailed content of Share a set of Go coding standards! Welcome to collect!. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:learnku.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template