### range(范围)
> go语言github项目:https://github.com/minibear2333/how_to_code
[TOC]
`range` 关键字在 `go` 语言中是相当常用好用的语法糖,可以用在 `for` 循环中迭代 `array`、`slice`、`map`、`channel`、`字符串`所有涉及到遍历输出的东西。
### 基本原理
### 怎么用?
我们在前一节[循环](https://mp.weixin.qq.com/s/hxeysXVCPKR7Wlql9D7YlA)中初次触及到了 `range`,也知道他可以省略`key`,或者省略`value`来循环遍历的特性,但是这种特性要结合实际情况考量该用哪一个。
**切片迭代**
```go
nums := []int{1, 2, 3}
for k, v := range nums {
fmt.Printf("key: %v , value: %v \n", k, v)
}
```
这和迭代方式非常适合用`for-range`语句,如果减少赋值,直接索引`num[key]`可以减少损耗。如下
```go
for k, _:= range nums {
```
**`map`迭代**
注意,从 `Go1`开始,遍历的起始节点就是随机了。
```go
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 所存储数据结构特征、结合实际情况进行。
**字符串迭代**(一个一个的输出字符)
```go
for k,v := range "hello"{
//注意这里单个字符输出的是ASCII码,
//用 %c 代表输出字符
fmt.Printf("key: %v , value: %c
\n", k, v)
}
```
**channel** (如果不会可以先 mark 下,详细参考后续:go 的并发特性章节)
```go
ch := make(chan int, 10)
ch <- 11
ch <- 12
close(ch) // 不用的时候记得关掉,不关掉又没有另一个goroutine存在会死锁哦,可以注释掉这一句体验死锁
for x := range ch {
fmt.Println(x)
}
```
**结构体**
```go
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`,原结构体不会发生任何变化!
```go
for _,v := range tmp{
v.a = 2
}
```
两次输出一致
```go
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`返回值会发生一次数据拷贝
- 安装与下载
- 投稿大纲
- 第一章、跑起来
- 为什么要学 go 语言?
- 让你的 Golang 项目在 IDE 里跑起来
- 第一个 go 程序
- go mod最佳实践
- 第二章、语言基础
- 声明【变量】的各种方式
- 常量+各种类型转换
- switch和type switch
- 循环语句的多种形式、死循环、break/continue
- range深度解析
- 第三章、函数和容器
- 函数简单使用和基本知识解析
- 匿名函数和闭包
- 可变参数
- 集合(map)
- 数组和切片
- 切片知识补充
- 第四章、指针、结构体、接口和异常处理
- 指针讨论
- 结构体
- 接口与多态
- 异常处理
- 第五章、再学一点运用自如
- 其他常用操作
- Go文件操作大全
- Go代码基本标准规范
- 切片排序sort包的使用
- Golang打镜像Dockerfile的写法
- 等待goroutine完成任务,循环中使用goroutine
- kinping.flag包读取命令行配置