Go コーディング標準のセットを共有してください。収集へようこそ!

藏色散人
リリース: 2022-12-09 17:10:05
転載
5598 人が閲覧しました

最近、プロジェクト内の多くの Go 言語コードをコードレビューしたので、メモの記録としてコードの仕様をまとめる必要があります。

前述したように、これは私たちのチームの単なる規範です。

今日は Go のコーディング標準について説明します。これは、パッケージ インジェクション/変数/定数の命名、基本構文、関数、エラー処理、エクスペリエンスなど、いくつかの主要なモジュールに大別されます。 [推奨: golang チュートリアル ]

1. コード スタイル

1.1 コード形式

  • コードは gofmt でフォーマットする必要があります。設定は自分で検索できます。
  • 記述するコードの各行は 120 文字を超えてはならず、超過部分は改行で解決する必要があります。
  • 1 つのファイルの最大行数は 800 行を超えません。
  • 1 つの関数の最大行数は 80 行を超えません。
  • インポート仕様
    • パッケージの導入に相対パスを使用しないでください。たとえば、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)
ログイン後にコピー
  • 構造体の初期化時に new(struct) の代わりに &struct を使用して、構造体の初期化との一貫性を確保し、構造体の初期化時に行を折り返します。
// bad
stu := new(S)
stu.Name = "张三"

// good
stu := &S{
    Name:"李四"
}
ログイン後にコピー
  • make を使用して、マップや配列などを宣言するときにコンテナの容量を指定して、コンテンツを事前に割り当てる必要があります。
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 エラー処理

  • 関数がエラーを返した場合、エラーを処理する必要があります。ビジネスで許可されている場合は、_ を使用してエラーを受け入れ、無視できます。対応する遅延は、明示的な処理を行わずに処理できます。
// 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 は、構成の読み取り、リンク ストレージ (redis、mysql など) などのサービスの開始前にのみ表示できます。
  • ビジネス コードではパニックではなくエラーを使用することをお勧めします。

1.5 単体テスト

  • 重要な関数ごとにテスト ケースを作成し、コードをマージするときにすべてのテストを自動的に実行する必要があります。
  • ファイルの名前は xxx_test.go です。
  • 関数の名前付けには、テスト関数名を使用することをお勧めします。

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 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:learnku.com
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート