成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Go 開發踩過的那些坑,你踩過幾個?

開發 前端
Go 能夠調用 SayHello 方法,調用 GetName() 時,在 return s.Name 報錯了,而不是在 GetName 的調用行數報錯。說明它走到方法里面了。問了下通義千問,大意是,方法并不屬于對象的內部數據結構,因此對 nil 訪問方法會轉到該結構體的方法表,但如果訪問 nil 的內部數據結構,則一定會拋 nil pointer reference。

一些基礎

Java 枚舉轉成 Go

Java

public enum DetectionMethodEnum {

    PROCESS_HASH("process_hash", "進程Hash檢測"),

    private final String type;
    private final String desc;

}


Go:

type DetectionMethod string

type DetectionMethodInfo struct {
    MethodType string
    Desc       string
}

const (
    ProcessHash  DetectionMethod = "PROCESS_HASH"
)

var DetectionMethodMap = map[DetectionMethod]DetectionMethodInfo{
    ProcessHash: {
        MethodType: "process_hash",
        Desc:       "進程Hash檢測"
    }
}

map 訪問

Java:

map.get(key)  or  map.getOrDefault(key, defaultValue)

Go:

if value, ok := map[key] ; ok {
   // ...code
}

強制類型轉換

注意,轉換為 *Struct 和 轉換為 Struct 并不等同。如果你的值是指針,那么轉換為結構體會報錯;反之亦然。

Java:

if (detectResultBase instanceof MemBackdoorDetectResult) {
            MemBackdoorDetectResult detectResult = (MemBackdoorDetectResult) detectResultBase;
            // ...code
}

Go

if memBackdoorDetectResult, ok := detectResultBase.(*result.MemBackdoorDetectResult) ; ok {
           // ...code
}

空指針引用

Java 的 NullPointerException 在 Go 變成了 nil pointer reference。

有兩個小區別:

  • 對 nil 進行 foreach , java 會報 NPE ,但是 Go 不會;
  • 對 nil 調用方法,java 會報 NPE, 但 Go 不會。

給定代碼如下:

  • range arr 時,Go 不會拋錯,java 會;
  • Go 能夠調用 SayHello 方法,調用 GetName() 時,在 return s.Name 報錯了,而不是在 GetName 的調用行數報錯。說明它走到方法里面了。問了下通義千問,大意是,方法并不屬于對象的內部數據結構,因此對 nil 訪問方法會轉到該結構體的方法表,但如果訪問 nil 的內部數據結構,則一定會拋 nil pointer reference
func TestBasic(t *testing.T) {
 var arr []int = nil
 for i := range arr {
  fmt.Println(i)
 }

 var stu *Stu
 stu.SayHello()
 fmt.Println(stu.GetName())
}

type Stu struct {
 Name string
}

func (s *Stu) SayHello() {
 fmt.Println("hello")
}

func (s *Stu) GetName() string {
 return s.Name
}

圖片圖片

圖片圖片

錯誤處理

Go 的錯誤處理與 Java 也有較大區別。

  • Go 通過返回和判斷單獨的 error 來進行錯誤,應用必須對錯誤處理。如果忽略錯誤,則程序會繼續往下走,直到走完流程,或者在其它地方遇到 panic 而終止。如果忽略錯誤(可使用 _ 表示),且沒有日志(類似 Java catch 了但是什么都不做),則程序什么都不輸出。就好像突然在哪里斷掉了,但是你沒法知道在哪里斷掉了。問題排查會很蛋疼且耗時。
  • Java 如果遇到運行時異常,會自動往上拋,遇到捕獲的就按照指定程序處理,沒有捕獲的繼續往上拋。如果沒有任何處理,則最終會拋出異常。如果捕獲了異常卻不處理,也會什么都不輸出,當然,這是自找罪受。

換句話說,Go 的錯誤如果忽略又不打日志,程序就會毫無輸出,對排查很不方便。這意味著:Go 做處理處理會比較繁瑣,每一個方法如果有錯誤就應該拋出,每一個錯誤都必須決定是否處理,還是繼續往上拋。益處是:能夠培養縝密的錯誤處理習慣。像 Java 那樣隨意,肯定會遭到懲罰。

Go 錯誤處理的一些推薦做法:

  • 前端錯誤,打印請求參數(為空可以不打),在 error 里返回錯誤碼和錯誤信息【強制】。
  • 存儲層方法,比如 repository ,必須返回 errror ,方便上層根據錯誤處理【強制】。
  • 檢測流程,創建出錯,直接終止流程,并返回 Error【強制】。
  • API (庫方法、數據庫、中間件、外部接口等)返回的錯誤必須捕獲處理,否則程序會無聲息終止【強制】。
  • 非數據庫錯誤,如果有錯誤碼的,返回錯誤碼和錯誤信息;沒有錯誤碼的,默認返回 InternalError 或 SystemError【推薦】。
  • 編寫工具類方法,推薦返回 error 【推薦】。
  • 上層方法,根據情形處理:如果不影響流程(局部失敗不影響整體失敗的情形),則打印錯誤日志,然后繼續往下走;如果影響流程,直接終止流程,拋出 error 。

Go 報錯

不得不說, Go 的報錯真的是有點不知所云。咋一看,看半天都看不出什么問題,真是費眼睛!因此,我總結了些常見報錯類型,方便以后更快排查。

重名類

可能是有兩個重名類 DO。比如有兩個同名類 A 和 B,本來應當引用 A,結果引用了 B。

Cannot use 'oldModels' (type []"xxx/internal/common/dal/service".T) as the type []"github.com/samber/lo".T

變量 models 與包名沖突

有時,你會發現包里確實聲明了這個變量、實例或結構體,但 IDE 就是報錯,找不到。很可能方法里的局部變量與包名沖突了。如下所示,有一個包名 models,又聲明了一個 models 變量,當然找不到啦!這種問題肉眼很難察覺。就像 Javascript 里,前面聲明了一個 password 變量,后面不小心寫成了 passord ,javascript 是不會報錯的(現在不知道會不會,好久沒寫 js 了)。

圖片圖片

反序列化錯誤

reason 字段的上報數據與類型定義不一致。

圖片圖片

存在包已經被刪除但引用沒有刪除

通常是因為之前在某個類里引用了某個包,后面又刪除了這個包,或者更改了包的位置導致。

圖片圖片

循環包引用

在 ”Go 包循環引用及對策[1] “ 一文里已經有講解過。

方法簽名不一致

類似問題可能是方法簽名不一致,比如方法函數簽名有返回值而實際傳入函數無返回值

cannot use calc (variable of type func()) as async.Consumer value in argument to taskExecutor.SubmitTask

函數參數沒有命名,只有類型

Function has both named and unnamed parameters '(ctx context.Context, []D)'

圖片圖片

方法實現不對

Go 沒有支持 lambda 表達式。寫慣了 Java 導致。

報錯:Invalid operation: func(key string) (*models.WhiteRuleDO,error) - (the operator - is not defined on func(key string) (*models.WhiteRuleDO, error))

Cannot use 'func(key string) (*models.WhiteRuleDO,error) ->' (type bool) as the type func(key string) (T, error)

圖片圖片

返回類型不一致

return whiteRulesInner, nil 處 報錯:Cannot use 'whiteRulesInner' (type []T) as the type *models.WhiteRuleDO

實際上 h.beyondLoginWhiteRuleCache.GetWithLoader 要返回的是 []*models.WhiteRuleDO 而不是 *models.WhiteRuleDO。

whiteRules, err := h.beyondLoginWhiteRuleCache.GetWithLoader(cacheKey, func(key string) (*models.WhiteRuleDO, error) {
        // ..code
        whiteRulesInner, err := h.whiteRuleService.List(ctx, whiteRuleQuery.Convert(ctx))
        if err != nil {
            return nil, err
        }
        return whiteRulesInner, nil
    })

JSON 反序列化

使用 Unmarshal 反序列化時,結構體的字段必須是首字母大寫,才能賦值成功,否則是默認值。

Unmarshal NPE

err := json_utils.Unmarshal(record.Value, fr) 報錯 ReadVal: can not read into nil pointer, error found

這個錯誤信息 "ReadVal: can not read into nil pointer, error found" 指的是在使用 json_utils.Unmarshal 進行 JSON 反序列化時,嘗試將 JSON 數據解碼到一個未初始化(nil)的指針變量 fr 中。

在 Go 語言中,如果有一個指針類型變量,如 *SomeStruct,在調用 Unmarshal 方法對 JSON 數據進行反序列化前,你需要確保該指針已經指向了一個實際的結構體實例,而不是 nil。

圖片圖片

字段未導出

報錯 reflect.Value.Interface: cannot return value obtained from unexported field or method

字段名需要改成首字母大寫。

func (e *ElementOperationHistoryDO) SetDetail(detail any) {
    if detail != nil {
        detailType := reflect.TypeOf(detail).String()
        struct_utils.SetFieldValue(detail, DetailType, detailType)
        e.DetailInfo = struct_utils.StructToMap(detail)
    }
}

func SetFieldValue(obj any, fieldName string, value any) {
    v := reflect.ValueOf(obj).Elem()
    if v.Kind() != reflect.Struct {
        return
    }

    field := v.FieldByName(fieldName)
    if !field.IsValid() {
        return
    }

    field.Set(reflect.ValueOf(value))
}

將 
detailInfo := &models.FileElementOperationDetailInfo{
        Fpath: v.FileResponseAgentParam.FileName,
}  傳給 detail

圖片圖片

實際參數多了

internal/ids_detect/eventflow/ability/UnifiedSsdeepDetect.go:157:62: got 3 type arguments but want 2

函數聲明了 2 個泛型參數,卻傳入了 3 個泛型參數。

圖片圖片

圖片圖片

Reference

[1]Go 包循環引用及對策:https://www.cnblogs.com/lovesqcc/p/18077717

責任編輯:武曉燕 來源: 編程大觀園
相關推薦

2025-04-29 10:17:42

2018-09-11 09:14:52

面試公司缺點

2023-03-13 13:36:00

Go擴容切片

2017-07-17 15:46:20

Oracle并行機制

2025-04-15 02:00:00

API版本項目

2018-01-10 13:40:03

數據庫MySQL表設計

2018-07-30 16:18:51

容災備份

2022-04-26 21:49:55

Spring事務數據庫

2024-05-06 00:00:00

緩存高并發數據

2015-03-24 16:29:55

默認線程池java

2025-02-10 00:27:54

2025-04-09 09:26:28

C 語言柔性數組編程

2018-08-01 14:45:16

PHP編程語言

2019-12-12 14:32:26

SQL語句數據庫

2020-05-18 08:58:33

Python開發工具

2020-11-03 13:50:31

Redis緩存數據庫

2025-05-27 08:45:00

2019-09-25 15:30:15

2024-06-26 10:37:05

2019-10-30 14:44:41

Prometheus開源監控系統
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 黑人精品 | 在线观看涩涩视频 | 中文字幕成人av | 免费看国产a | 午夜免费电影 | 久久久久国产精品午夜一区 | 中国一级大毛片 | 美女国产精品 | 国产精品久久久久久久久久久久午夜片 | 国产精品久久 | 99伊人| 免费成人在线网站 | 久久久久久久久一区 | 一区二区久久电影 | 九九精品在线 | 美国一级黄色片 | 国产真实乱全部视频 | 国产欧美精品一区二区三区 | 日韩网 | 成人精品免费 | 久久久99国产精品免费 | 91视频在线观看 | 国产成人精品视频在线观看 | 日日夜夜天天 | 久久久精品一区二区三区四季av | 激情婷婷 | 黄色成人在线观看 | 午夜av电影院 | 日韩美香港a一级毛片免费 国产综合av | 一区二区三区不卡视频 | 国产超碰人人爽人人做人人爱 | 国产精品久久久亚洲 | 久久成人精品一区二区三区 | 亚洲xx在线 | 日韩免费视频一区二区 | 日日干日日色 | 亚洲精品一区二区网址 | 成人精品国产一区二区4080 | 欧美极品少妇xxxxⅹ免费视频 | 日韩一级 | 人人看人人搞 |