goland提取方法與...interface{}類型的注意點

本文首發於我的Github博客
本文記錄了作者在使用goland提供的提取方法(Extract Method)功能時,由於...interface{}的類型問題而遭遇到的bug和一點感悟,簡單來說:

  • 可變長的參數會被goland的Extract Method轉化爲切片(slice),比如...interface{}會被轉化爲[]interface{}
  • 由於interface{}的特殊性,需要額外注意

bug的產生

在代碼中有如下片段

func f(payload ...interface{}) {
    for _, p := range payload {
        // do something
    }
}

現在想要將循環提取出來,作爲一個方法,在goland中可以直接選中文本然後Extract Method,但是結果是這樣的

func f(payload ...interface{}) {
    ExtractedMethod(payload)
}

func ExtractedMethod(payload []interface{}) {
    for _, p := range payload {
        // do something
    }
}

期望中的函數簽名是ExtractedMethod(payload ...interface{}),不符合預期,所以要進行修改

// WRONG!!!!!!!!

func f(payload ...interface{}) {
    ExtractedMethod(payload)
}

func ExtractedMethod(payload ...interface{}) {
    for _, p := range payload {
        // do something
    }
}

上述的代碼不會有編譯錯誤,但是是完全不符合預期的,爲什麼呢?

bug的原因

// WRONG!!!!!!!!

func f(payload ...interface{}) {
    // we need to unpack payload
    ExtractedMethod(payload)
}

func ExtractedMethod(payload ...interface{}) {
    for _, p := range payload {
        // do something
    }
}

如上述註釋所說,我們需要對f中傳遞給ExtractedMethod的參數payload做一個解包工作,因爲

  • 我們f函數的本意是要用ExtractedMehtodpayload中的每一個元素做處理
  • 現在不解包,payload原本一個[]interface{}又被額外自動包裝了一層,成爲了interface{}傳遞給了ExtractedMethod,只會對整個payload做一次處理

bug的解決與思考

將代碼修改爲如下後正確

func f(payload ...interface{}) {
    ExtractedMethod(payload...)
}

func ExtractedMethod(payload ...interface{}) {
    for _, p := range payload {
        // do something
    }
}

以後可以採取的方法是,先將傳參的地方payload改爲payload...,這樣的話如果忘記修改參數[]interface{}...interface{},是會有編譯器報錯的

這個修改順序可以讓編譯器爲我們保駕

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章