本文首發於我的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
函數的本意是要用ExtractedMehtod
對payload
中的每一個元素做處理 - 現在不解包,
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{}
,是會有編譯器報錯的
這個修改順序可以讓編譯器爲我們保駕