range语句
目录
range slice
func main() {
s := []int{1, 2, 3}
for i := 0; i < len(s); i++ {
if i == 1 {
s = append(s, 4)
}
fmt.Println(i, s[i])
}
}
上面的代码,遍历中新增元素是没有问题的。 但是下面的range遍历,结果是不一样的:
func main() {
s := []int{1, 2, 3}
fmt.Println(s) //[1 2 3]
for i, v := range s {
if i == 0 {
s = append(s, 4)
}
fmt.Println(s) //[1 2 3 4]
fmt.Println(i, v)
}
fmt.Println(s) //[1 2 3 4]
}
这里在range中增加元素,并没有改变range的次数。 其实这里只是一个语法糖。 对于切片的for…range底层源码是这样的:
// for_temp := range
// len_temp := len(for_temp)
// for index_temp = 0; index_temp < len_temp; index_temp++ {
// value_temp = for_temp[index_temp]
// index = index_temp
// value = value_temp
// original body
// }
可以看到,在遍历之前,就取到了切片的长度。后面增删元素,并不影响遍历的次数。
仅仅不会改变遍历的次数,但是切片里的数据是会改动的,所以不要在遍历的时候删除数据。
range map
// Lower a for range over a map.
// The loop we generate:
// var hiter map_iteration_struct
// for mapiterinit(type, range, &hiter); hiter.key != nil; mapiternext(&hiter) {
// index_temp = *hiter.key
// value_temp = *hiter.val
// index = index_temp
// value = value_temp
// original body
// }
func mtest() {
m := make(map[int]int)
m[0] = 1
m[1] = 2
var count int
for k, v := range m {
fmt.Println(k, v)
count++
if count == 1 {
m[3] = 3
fmt.Println("add")
}
}
}
输出:
0 1
add
1 2
3 3
可以看出,range过程中增加元素是会改变range次数的。实验证明,删除元素也有同样的效果。
range channel
// Lower a for range over a channel.
// The loop we generate:
// for {
// index_temp, ok_temp = <-range
// if !ok_temp {
// break
// }
// index = index_temp
// original body
// }
range array
// Lower a for range over an array.
// The loop we generate:
// len_temp := len(range)
// range_temp := range
// for index_temp = 0; index_temp < len_temp; index_temp++ {
// value_temp = range_temp[index_temp]
// index = index_temp
// value = value_temp
// original body
// }
可以看到输入值和slice类似,都是提前取到长度。
range string
// Lower a for range over a string.
// The loop we generate:
// len_temp := len(range)
// var next_index_temp int
// for index_temp = 0; index_temp < len_temp; index_temp = next_index_temp {
// value_temp = rune(range[index_temp])
// if value_temp < utf8.RuneSelf {
// next_index_temp = index_temp + 1
// } else {
// value_temp, next_index_temp = decoderune(range, index_temp)
// }
// index = index_temp
// value = value_temp
// // original body
// }
func stringtest() {
s := "abcd"
var count int
for _, v := range s {
fmt.Printf("%c\n", v)
count++
if count == 1 {
s = s + "ss"
fmt.Println("add")
}
}
fmt.Println(s)
}
验证的结果为range过程中对字符串的追加及截取,都不影响range。