Heim  >  Artikel  >  Backend-Entwicklung  >  Teilen Sie eine Reihe von Go-Codierungsstandards! Willkommen zum Sammeln!

Teilen Sie eine Reihe von Go-Codierungsstandards! Willkommen zum Sammeln!

藏色散人
藏色散人nach vorne
2022-12-09 17:08:425592Durchsuche

Vor kurzem habe ich im Projekt viele Go-Sprachcodes überprüft. Es ist notwendig, die Codespezifikationen zusammenzufassen, die als Notizdatensatz betrachtet werden können.

Wie bereits erwähnt handelt es sich dabei lediglich um eine Reihe von Normen für unser Team.

Heute sprechen wir über die Codierungsstandards von Go, die grob in mehrere Hauptmodule unterteilt sind, wie z. B. Paketnotizen/Variablen-/Konstantenbenennung, grundlegende Syntax, Funktionen, Fehlerbehandlung, Erfahrung usw. [Empfohlen: golang-Tutorial

1.1 Codeformat

Der Code muss mit gofmt formatiert werden. Sie können selbst nach der Konfiguration suchen

    Der Code, den wir schreiben sollten 1 Zeile pro Zeile darf nicht überschritten werden. Überschüssige Zeichen werden durch Zeilenumbrüche aufgelöst.
  • Die maximale Anzahl von Zeilen in einer einzelnen Datei überschreitet nicht 800 Zeilen.
  • Die maximale Anzahl von Zeilen in einer einzelnen Funktion überschreitet nicht 80 Zeilen.
  • Importspezifikation
  • Verwenden Sie beispielsweise keine relativen Pfade, um Pakete einzuführen
    • Wenn beim Importieren eines Pakets mehrere identische Paketnamen in Konflikt geraten, müssen Sie Import-Aliase verwenden.import ../util/net
    • // bad
      "github.com/google/uuid"
      
      // good
      uuid "github.com/google/uuid"
  • Importierte Pakete werden empfohlen gruppiert und verweist auf anonyme Pakete. Es wird empfohlen, eine neue Gruppe zu verwenden und Kommentare hinzuzufügen, um das spätere Lesen durch Freunde zu erleichtern
    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 Deklaration, Initialisierung und Definition
  • Wenn eine Funktion mehrere Variablen verwenden muss, können Sie die var-Deklaration verwenden am Anfang der Funktion. Außerhalb der Funktion deklarierte Variablen können := nicht verwenden, was zu Fallstricken führen kann. Wenn Sie es nicht wissen, können Sie eine Nachricht im Kommentarbereich hinterlassen (das ist nicht einfach zu kommentieren)!

      var (
          port = 8081
          metricServerPort = 2001)
    • Verwenden Sie &struct anstelle von new(struct), wenn Sie die Struktur initialisieren, um sicherzustellen, dass sie mit der Initialisierung der Struktur konsistent ist, und brechen Sie die Zeile beim Initialisieren der Struktur um.
        // bad
        stu := new(S)
        stu.Name = "张三"
        
        // good
        stu := &S{
            Name:"李四"
        }
      • Verwenden Sie make, um die Kapazität des Containers anzugeben, wenn Sie eine Karte, ein Array usw. deklarieren, um den Inhalt vorab zuzuweisen.
        users := make(map[int]string, 10)tags := make([]int, 0, 10)
      • Verwenden Sie das Standardschlüsselwort var und geben Sie keinen Typ an, es sei denn, dieser unterscheidet sich vom Typ des Ausdrucks.
          // bad
          var _f string F()
          
          func F() string {
              return "hello world!"
          }
          
          // good 
          var _f F()
          
          func F() string {
              return "hello world!"
          }
        • 1.3 Fehlerverarbeitung

        Wenn die Funktion einen Fehler zurückgibt, muss der Fehler verarbeitet werden. Wenn das Unternehmen dies zulässt, können Sie ihn mit _ akzeptieren und ignorieren. Die entsprechende Verzögerung kann ohne explizite Verarbeitung verarbeitet werden.

          // bad
          func InitConfig() error {
              ...
          }
          InitConfig()
          
          
          // good
          func InitConfig() error {
              ...
          }
          err := InitConfig()
          if err != nil {
              ...
          }
          // or 
          _ := InitConfig()
        • error muss als letzter Parameter zurückgegeben werden, wenn er als Rückgabewert verwendet wird
          // bad
          func InitConfig() (error,int) {
              ...
          }
          
          // good 
          func InitConfig() (int, error) {
              ...
          }
        • Fehler müssen separat behandelt werden und dürfen nicht mit anderer Logik gekoppelt werden.
          // 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 Panikbehandlung

        Es ist verboten, Panikfehler im Geschäftscode zu werfen.

          Panik darf nur auftreten, bevor der Dienst gestartet wird, z. B. beim Lesen der Konfiguration, beim Linkspeichern (Redis, MySQL usw.).
        • Es wird empfohlen, im Geschäftscode Fehler statt Panik zu verwenden.
        • 1.5 Unit Test

        Für jede wichtige Funktion muss ein Testfall geschrieben werden und alle Tests müssen beim Zusammenführen des Codes automatisch ausgeführt werden.

          Die Datei heißt xxx_test.go.
        • Es wird empfohlen, bei der Benennung von Funktionen den Namen der Testfunktion zu verwenden.
        2. Namenskonventionen

        In jeder Sprache sind Namenskonventionen in Codespezifikationen sehr wichtig. Eine einheitliche und genaue Benennung kann nicht nur die Lesbarkeit des Codes verbessern, sondern den Menschen auch das Gefühl geben, dass dieser Genosse wirklich weiß, wie es zu tun. Ochse!

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

        Das obige ist der detaillierte Inhalt vonTeilen Sie eine Reihe von Go-Codierungsstandards! Willkommen zum Sammeln!. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

      • Stellungnahme:
        Dieser Artikel ist reproduziert unter:learnku.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen