
最近在工作中發現一個坑,關鍵是這個坑還不報錯,所以在此記錄一下,順便也對相關知識點做一個總結。
關于這個坑,還得從「不定參數」說起。
不定參數?
不定參數,顧名思義,也就是「參數個數不確定」的時候golang支持的一種機制。
舉個例子?
我們想實現一個多個數字累加的方法,既然是多個數字,那么數字的個數肯定是不確定的,所以我們可以如下編寫。
func NumberSum(args ...int) (res int) { //不定參數的使用示例
for i := range args {
res += i
}
return res
}
func main() {
total := NumberSum(1, 2, 3, 4, 5, 6)
fmt.Println(total)
}
//輸出結果
15
通過上面的示例我們可以看出不定參數的使用還是很簡單的,只要在參數定義的時候,在「類型前面加上三個點」就可以了。但是不定參數在使用的時候還有其他需要注意的問題需要注意一下。
- 所有的不定參數類型必須是相同的。
- 不定參數必須是函數的最后一個參數。
- 不定參數在函數體內相當于一個切片,對切片的操作同樣適合對不定參數的操作。(比如上述例子中,是可以對args做「for range」操作的)。
- 切片也可以作為參數傳遞給不定參數,切片名稱后面要加上“...”。
前面三點其實還是比較好理解的,針對第四點看看下面例子,也是「容易出問題」的地方,而且本文要說的「坑」也和這個有關。
func NumberSum(args ...int) (res int) {
for i := range args {
res += i
}
return res
}
func main() {
//定義了一個切片,準備傳給不一定參數
numSelice := []int{1, 2, 3, 4, 5, 6}
//把切片傳給不定參數的時候,需要在參數后面加上...
total := NumberSum(numSelice...)
fmt.Println(total)
}
通過上述例子咱們應該已經對不定參數有了一定的掌握,接下來咱們看一個特殊的場景 如果「不定參數的各個參數類型不一樣」怎么辦?這種場景其實還是很常見的,用interface類型即可解決。比如我們要封裝一個生成rediskey的方法。?
func MakeRedisKey(key string, args ...interface{}) (redisKey string) {
redisKey = fmt.Sprintf(key, args)
return redisKey
}
func main() {
ucid := 123
name := "test"
key := "key_id_%d_name_%s"
redisKey := MakeRedisKey(key, ucid, name)
fmt.Println(redisKey)
}
//輸出結果
key_id_[123 %!d(string=test)]_name_%!s(MISSING)
上面的代碼看似沒有問題,但是輸出結果卻看似來就像亂碼一樣,這是為什么呢?我們來分析一下
- 我們在main函數中調用「MakeRedisKey」函數的時候傳進去的「ucid和name」都為不定參數。
- 「在MakeRedisKey函數中」,打印出來的args的類型為「切片」類型,也就是 []interface {}。
- 我們看一下「fmt.Sprintf」函數的定義。
func Sprintf(format string, a ...interface{}) string {
........內容是什么不重要
return s
}
我們會發現Sprintf的第二個參數也是「不定參數」。
這就相當于在「MakeRedisKey」中,我們拿著「切片類型」的參數args,去傳給一個「不定參數」作為參數,按照我們上面總結的**把切片傳給不定參數的時候,需要在參數后面加上...**這條定律,上面代碼改成如下即可正常。
func MakeRedisKey(key string, args ...interface{}) (redisKey string) {
redisKey = fmt.Sprintf(key, args...) //在args后面加上...
return redisKey
}
func main() {
ucid := 123
name := "test"
key := "key_id_%d_name_%s"
redisKey := MakeRedisKey(key, ucid, name)
fmt.Println(redisKey)
}
//輸出結果
key_id_123_name_test
這樣我們就可以得到正常的結果了。最后總結一下,「我們在使用不定參數的時候,尤其是涉及到多次傳遞的時候,一定不要想當然,記得在中間傳遞過程中在參數后面加上...」。