<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                # Go編碼規范(uber) ##指向接口的指針 ```go // 接口使用值傳遞 // 接口包含兩部分: // 1.指向類型信息的指針 // 2.數據指針,如果存儲的數據為指針,則直接存儲,否則存儲指向數據的指針 ``` ## 接收者與接口 ```go type S struct { data string } // 可以被實例或指針調用 func (s S) Read() string { return s.data } // 只能被指針調用 func (s *S) Write(str string) { s.data = str } ``` ## Mutex默認值 ```go // sync.Mutex和sync.RWMutex的默認值可用,無需使用指針 // 如果使用指針指向struct,mutex可能為空字段 // bad m := new(sync.Mutex) // good var m sync.Mutex // 結構體不導出時可直接嵌套 type smap struct { sync.Mutex } // 結構體導出時,使用名稱決定是否導出 type SMap struct { m sync.Mutex } ``` ## 復制切片和Map ```go // 切片和map自帶指針指向底層數據結構,傳遞時需注意 func (d *Driver) SetTrips(trips []Trip) { d.trips = make([]Trip, len(trips)) copy(d.trips, trips) } ``` ## 使用defer收尾 ```go p.Lock() defer p.Unlock() ... return ``` ## Channel大小 ```go // Channel要么為1要么為0,其他大小需要考慮用什么防止Channel填滿并阻止寫入,以及發生這種情況時會發生什么 // 1 c := make(chan int, 1) // 無緩存 c := make(chan int) ``` ## 從1開始枚舉 ```go // 使用const和iota定義枚舉,一般不以0開始 const ( Add = iota + 1 Sub ) // 在一些情況下,如0表示默認值等可以使用0開始 ``` ## Error類型 ```go // 簡單的字符串error,無需多余信息 errors.New // 格式化的字符串 fmt.Errorf // 自定義類型實現Error()方法即可,可交給客戶端檢測和處理 // 使用errors.Wrap包裹 // 傳遞由內層函數return的error適用 // Wrap改變cause和other字段,Wrap調用的位置會存儲在error棧里 func Wrap(other, newDescriptive error) error { err := &Err{ previous: other, // error棧里上個error cause: newDescriptive, // error的原因 } err.SetLocation(1) return err } // 使用var聲明和初始化error方便調用方檢測 var ErrCouldNotOpen = errors.New("could not open") if err := f(); err != nil { if err == ErrCouldNotOpen { // handle } else { panic("unknown error") } } // 使用自定義類型傳遞更多信息 type errNotFound struct { file string } func (e errNotFound) Error() string { return fmt.Sprintf("file %q not found", e.file) } func open(file string) error { return errNotFound{file: file} } func use() { if err := open(); err != nil { if _, ok := err.(errNotFound); ok { // handle } else { panic("unknown error") } } } // 作為公共API的一部分可以提供檢測函數方便別人調用 func IsNotFoundError(err error) bool { _, ok := err.(errNotFound) return ok } ``` ## 處理類型斷言 ```go t, ok := i.(string) if !ok { // handle } ``` ## 勿panic ```go // 生產環境下的代碼需要避免panic,容易導致聯級錯誤 // 如果發生錯誤,則函數返回error讓調用者處理 // panic/recover不是處理錯誤的手段,只有在無法解決時panic // 如空引用 // 有一個例外,程序初始化時,有錯誤直接panic掉退出程序 // 在測試中,使用Fatal或FailNow來明顯標記失敗 f, err := ioutil.TempFile("", "test") if err != nil { t.Fatal("failed to set up test") } ``` ##使用strconv ```go // strconv比fmt更快 // 避免頻繁string與byte轉化,一次性轉化使用 ``` # 代碼風格 ## 導入 ```go // 類似的分組聲明 // 不相關的另起一組 import ( "a" "b" ) const ( a = 1 b = 2 ) const ENV = "env" // func內也可用這種寫法 var ( a = 1 b = 2 ) type ( Area float64 Volume float64 ) // 導入順序 // 1.標準庫 // 2.其他 import ( "fmt" "os" "go.uber.org/atomic" "golang.org/x/sync/errgroup" ) ``` ## 包名 ```go // 包名全小寫,無下劃線,非復數,夠簡潔,大多情況下被導入無需重命名 // 避免common、util、shared、lib等指代不明的命名 // 導入的包名最后不符合時需重命名 ``` ## 函數名 ```go // 駝峰命名 // 測試函數可包含下劃線 ``` ## 函數組織 ```go // 同文件內根據接收者分組 // 導出的函數盡可能靠前,在struct、const、var之后 // newXX()函數可在struct后,其他函數前 // 單個功能性函數靠后 ``` ## 全局變量聲明 ```go // 表達式足夠清晰時,不指定類型 // 為不導出的全局變量或常量加下劃線前綴 // 為不導出的error,用err前綴 var _s = F() func F() string { return "A" } // 不直觀時寫明類型 var _e error = F() func F() myError { return myError{} } ``` ## 結構體嵌入 ```go // 嵌入的結構體應該靠前,并使用空行與其他類型字段區分 type Client struct { http.Client version int } // 初始化時使用字段名字 k := User{ FirstName: "John", LastName: "Doe", Admin: true, } ``` ## 本地變量聲明 ```go // 明確賦值使用:= s := "str" // 默認值明確使用var // 使用var聲明的切片可以直接使用,無需make var s []int ``` ## nil是有效的切片 ```go // nil是有效的切片,長度為0 // 無需返回長度為0的切片 if x == "" { return nil // []int{} } // 檢查切片是否為空時,使用len(),而不是nil func isEmpty(s []string) bool { return len(s) == 0 // s == nil } ``` ## 縮小變量作用域 ```go if err := ioutil.WriteFile(name, data, 0644); err != nil { return err } ``` ## 避免使用不明參數 ```go // 使用/* */讓參數可讀性更高 // func printInfo(name string, isLocal, done bool) printInfo("foo", true /* isLocal */, true /* done */) // 使用自定義類型,讓參數可讀性更高并保證類型安全 type Region int func printInfo(name string, region Region) ``` ## 避免轉義 ```go // 使用原生字符串 wantErr := `unkown "text"` ``` ## 初始化結構體引用 ```go // 使用&保持一致,而不是new sval := T{Name: "foo"} sptr := &T{Name: "bar"} ``` ## 格式化字符串 ```go // 在函數外聲明格式化用字符串加const const msg = "%v %v\n" fmt.Printf(msg, 1, 2) ``` # 模式 ## 測試表 ```go // 測試數據使用表的形式,測試邏輯保持簡潔 tests := []struct{ give string wantHost string wantPort string }{ { give: "192.0.2.0:8000", wantHost: "192.0.2.0", wantPort: "8000", }, { give: "192.0.2.0:http", wantHost: "192.0.2.0", wantPort: "http", }, { give: ":8000", wantHost: "", wantPort: "8000", }, { give: "1:8", wantHost: "1", wantPort: "8", }, } for _, tt := range tests { t.Run(tt.give, func(t *testing.T) { host, port, err := net.SplitHostPort(tt.give) require.NoError(t, err) assert.Equal(t, tt.wantHost, host) assert.Equal(t, tt.wantPort, port) }) } ``` ## 功能性選項 ```go // 在可遇見的會多傳入的可選參數 // bad func Connect( addr string, timeout time.Duration, caching bool, ) (*Connection, error) { // ... } // Timeout與caching必須提供 db.Connect(addr, db.DefaultTimeout, db.DefaultCaching) db.Connect(addr, newTimeout, db.DefaultCaching) db.Connect(addr, db.DefaultTimeout, false /* caching */) db.Connect(addr, newTimeout, false /* caching */) // good type options struct { timeout time.Duration caching bool } // Option重新定義connect內行為 type Option interface { apply(*options) } type optionFunc func(*options) func (f optionFunc) apply(o *options) { f(o) } func WithTimeout(t time.Duration) Option { return optionFunc(func(o *options) { o.timeout = t }) } func WithCaching(cache bool) Option { return optionFunc(func(o *options) { o.caching = cache }) } func Connect( addr string, opts ...Option, ) (*Connection, error) { options := options{ timeout: defaultTimeout, caching: defaultCaching, } for _, o := range opts { o.apply(&options) } // ... } // Options使用時才用提供 db.Connect(addr) db.Connect(addr, db.WithTimeout(newTimeout)) db.Connect(addr, db.WithCaching(false)) db.Connect( addr, db.WithCaching(false), db.WithTimeout(newTimeout), ) ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看