range 關鍵字在 go 語言中是相當常用好用的語法糖,可以用在 for 循環中迭代 array、slice、map、channel、字符串所有涉及到遍歷輸出的東西。
基本原理
怎么用?
我們在前一節循環中初次觸及到了 range,也知道他可以省略key,或者省略value來循環遍歷的特性,但是這種特性要結合實際情況考量該用哪一個。
切片迭代
nums := []int{1, 2, 3} for k, v := range nums { fmt.Printf("key: %v , value: %v \n", k, v) }
這和迭代方式非常適合用for-range語句,如果減少賦值,直接索引num[key]可以減少損耗。如下
for k, _:= range nums {
map迭代注意,從 Go1開始,遍歷的起始節點就是隨機了。
kvs := map[string]string{ "a":"a", "b":"b", } for k, v := range kvs { fmt.Printf("key: %v , value: %v \n", k, v) }
函數中for-range語句中只獲取 key 值,然后跟據 key 值獲取 value 值,雖然看似減少了一次賦值,但通過 key 值查找 value 值的性能消耗可能高于賦值消耗。
所以能否優化取決于 map 所存儲數據結構特征、結合實際情況進行。
字符串迭代(一個一個的輸出字符)
for k,v := range "hello"{ //注意這里單個字符輸出的是ASCII碼, //用 %c 代表輸出字符 fmt.Printf("key: %v , value: %c \n", k, v) }
channel (如果不會可以先 mark 下,詳細參考后續:go 的并發特性章節)
ch := make(chan int, 10) ch <- 11 ch <- 12 close(ch) // 不用的時候記得關掉,不關掉又沒有另一個goroutine存在會死鎖哦,可以注釋掉這一句體驗死鎖 for x := range ch { fmt.Println(x) }
結構體
tmp := []struct{ int string }{ {1, "a"}, {2, "b"}, } for k,v := range tmp{ fmt.Printf("k:%v, v:%v \n",k,v) }
注意:由于循環開始前循環次數就已經確定了,所以循環過程中新添加的元素是沒辦法遍歷到的。
有可能會遇到的坑!
由于range遍歷時value是值的拷貝,如果這個時候遍歷上一節聲明的結構體時,修改value,原結構體不會發生任何變化!
for _,v := range tmp{ v.a = 2 }
兩次輸出一致
k:0, v:{1 a} k:1, v:{2 b} k:0, v:{1 a} k:1, v:{2 b}
編程 Tips
- 遍歷過程中可以適情況放棄接收 index 或 value,可以一定程度上提升性能
- 遍歷 channel 時,如果 channel 中沒有數據,可能會阻塞
- 盡量避免遍歷過程中修改原數據
總結
- range可以用于for 循環中迭代 array、slice、map、channel、字符串所有涉及到遍歷輸出的東西。
- for-range 的實現實際上是C風格的for循環
- 使用index,value接收range返回值會發生一次數據拷貝
掃碼二維碼 獲取免費視頻學習資料
- 本文固定鏈接: http://phpxs.com/post/7379/
- 轉載請注明:轉載必須在正文中標注并保留原文鏈接
- 掃碼: 掃上方二維碼獲取免費視頻資料
查 看2022高級編程視頻教程免費獲取