Go 知识for-range

Go 知识for-range

  • [1. for-range 的用法](#1. for-range 的用法)
    • [1.1 数组](#1.1 数组)
    • [1.2 切片](#1.2 切片)
    • [1.3 字符串](#1.3 字符串)
    • [1.4 map](#1.4 map)
    • [1.5 chan](#1.5 chan)
  • [2. 原理](#2. 原理)
    • [2.1 数组](#2.1 数组)
    • [2.2 切片](#2.2 切片)
    • [2.3 字符串](#2.3 字符串)
    • [2.4 map](#2.4 map)
    • [2.5 chan](#2.5 chan)
  • [3. 总结](#3. 总结)

https://a18792721831.github.io/

1. for-range 的用法

for-range 表达式用于遍历集合元素,比传统的for更加简单直观。

for-range 的表达式一般格式:

Go 复制代码
    for index, value := range data {
        //....
    }

for-range 一般可以返回两个值,对于不同类型的data有不同的返回值。

对于数组,返回下标和值。

对于切片,返回下标和值。

对于string,返回下标和值。

对于map,返回key和value。

对于chan,返回值,只会返回一个元素。

1.1 数组

Go 复制代码
	arr := [5]int{1, 2, 3, 4, 5}
	for i := range arr {
		fmt.Println(arr[i])
	}
	fmt.Println()
	for i, v := range arr {
		fmt.Printf("i=%d,v=%d\n", i, v)
	}

1.2 切片

Go 复制代码
	arr := []int{1, 2, 3, 4, 5}
	for i := range arr {
		fmt.Println(arr[i])
	}
	fmt.Println()
	arr = append(arr, 6, 7, 8, 9)
	for i, v := range arr {
		fmt.Printf("i=%d,v=%d\n", i, v)
	}

1.3 字符串

Go 复制代码
	str := "hello world"
	for i := range str {
		fmt.Println(str[i])
	}
	fmt.Println()
	for i, v := range str {
		fmt.Printf("i=%d,v=%c\n", i, v)
	}

需要注意的是,对于中英文,因为编码的方式不同,每个字符的占用空间不同,就会出现下标不连续的问题。

Go 复制代码
	str := "你好,世界"
	for i := range str {
		fmt.Println(str[i])
	}
	fmt.Println()
	for i, v := range str {
		fmt.Printf("i=%d,v=%c\n", i, v)
	}

1.4 map

Go 复制代码
	str := map[string]int{
		"one":   1,
		"two":   2,
		"three": 3,
		"four":  4,
		"five":  5,
	}
	for i := range str {
		fmt.Println(str[i])
	}
	fmt.Println()
	for k, v := range str {
		fmt.Printf("i=%s,v=%d\n", k, v)
	}

1.5 chan

Go 复制代码
	ch := make(chan string, 10)
	ch <- "h"
	ch <- "e"
	ch <- "l"
	ch <- "l"
	ch <- "o"
	for i := range ch {
		fmt.Println(i)
	}
	//fmt.Println()
	//for k, v := range ch {
	//	fmt.Printf("i=%s,v=%d\n", k, v)
	//}

因为chan里面没有数据了,所以就阻塞了,并不会自动结束哦。

当你视图用两个变量接收返回值的时候,就会编译失败

2. 原理

for-range是在编译的时候,转换为传统的for语句。

需要注意,下面都是伪代码,使用常见的语法规则进行描述。

因为在for-range中使用了 := 短定义并赋值的方式,所以使用for-range的时候,第二个值会进行变量拷贝,对于大数据的for-range,可能会导致性能变差。

2.1 数组

Go 复制代码
    len_temp := len(arr)
    data := arr
    for index_temp = 0; index_temp < len_temp; index_temp++ {
        value_temp = data[index_temp]
        index = index_temp
        value = value_temp
        // 执行 for-range 里面的代码
        // .....
    }

需要注意的一个,在数组中,len和cap是两个值,如果len=5,cap=10,在遍历过程中,对于第6个元素进行赋值,那么是无法遍历到的。因为在遍历开始的时候,就已经使用len获取到了遍历范围了。

2.2 切片

Go 复制代码
    len_temp := len(sli)
    data := sli
    for index_temp = 0; index_temp < len_temp; index_temp++ {
        value_temp = data[index_temp]
        index = index_temp
        value = value_temp
        // 执行 for-range 里面的代码
        // .....
    }

切片与数组基本上相同。

2.3 字符串

Go 复制代码
    len_temp := len(str)
    var next_index_temp int
    for index_temp = 0; index_temp < len_temp; index_temp = nex_index_temp {
        value_temp = rune(str[index_temp])
        if value_temp < utf8.RuneSize {
            next_index_temp = index_temp + 1
        } else {
            value_temp, next_index_temp = decoderune(str, index_temp)
        }
        index = index_temp
        value = value_temp
        // 执行 for-range 里面的代码
        // .....
    }

因为不同的字符集,占用的长度不同,所以这里会对是否是utf8字符集字符进行判断,并进行不同的处理。

比如:

2.4 map

Go 复制代码
    var temp *map
    init_map(type, data, &temp)
    for ; temp != nil; temp = iter_next() {
        index_temp = *temp.key
        value_temp = *temp.value
        index = index_temp
        value = value_temp
        // 执行 for-range 里面的代码
        // .....
    } 

map的遍历是无序的,同时不会指定次数,但是同样需要避免在遍历过程中,操作map。

2.5 chan

Go 复制代码
    for {
        index_temp, ok = <- ch
        if !ok {
            break
        }
        index = index_temp
        // 执行 for-range 里面的代码
        // .....
    }

可以看到遍历chan,最终依然是使用操作符<-读取数据的,但是会对第二个值进行判断,所以可以保证for-range返回的值都是成功读取的值,当没有数据读取的时候,依然会因为操作符<-阻塞。

3. 总结

总的来说,for-range和java里面的for-each是类似的,原理都可以理解为语法糖,在编译的时候再进行替换。

相关推荐
hkNaruto3 小时前
【P2P】【Go】采用go语言实现udp hole punching 打洞 传输速度测试 ping测试
golang·udp·p2p
入 梦皆星河3 小时前
go中常用的处理json的库
golang
海绵波波1075 小时前
Gin-vue-admin(2):项目初始化
vue.js·golang·gin
每天写点bug5 小时前
【go每日一题】:并发任务调度器
开发语言·后端·golang
一个不秃头的 程序员5 小时前
代码加入SFTP Go ---(小白篇5)
开发语言·后端·golang
基哥的奋斗历程6 小时前
初识Go语言
开发语言·后端·golang
自在的LEE6 小时前
当 Go 遇上 Windows:15.625ms 的时间更新困局
后端·kubernetes·go
ZVAyIVqt0UFji12 小时前
go-zero负载均衡实现原理
运维·开发语言·后端·golang·负载均衡
唐墨12316 小时前
golang自定义MarshalJSON、UnmarshalJSON 原理和技巧
开发语言·后端·golang
老大白菜17 小时前
FastAPI vs Go 性能对比分析
开发语言·golang·fastapi