## go语言中的for循环
*假如给你一个字符串让你遍历获取其中的内容,或者查找其中的是否包含某个字符串,你会如何做?*
#### 理所当然的我们选择了for循环来进行遍历
在go语言中使用比较多的两个循环一个是**for i**,一个是**for range**,这两者都能够很有效的对一个集合体进行遍历。(string也是一个集合体),下面我们来具体展示一下他们之间的区别
#### for i
```go
func main() {
str := "Hello, 世界"
for i := 0; i < len(str); i++ {
ch := str[i]
fmt.Println(i, ch, , string(ch))
}
}
```
这是一段很简单的代码,首先思考一下他的答案是什么?
```json
0 72 H
1 101 e
2 108 l
3 108 l
4 111 o
5 44 ,
6 32
7 228 ä
8 184 ¸
9 150
10 231 ç
11 149
12 140
```
这是它的答案,为什么会产生这么一个结果?
首先需要了解一下字符串在go语言的具体实现,简单的来说字符串是一系列8位字节的集合,一般以UTF-8的编码格式,看一下go的源码中`src/runtime/string.go`,string的定义如下
```go
type stringStruct struct {
str unsafe.Pointer
len int
}
```
string由两部分组成一个是指针,一个是长度,指针指向一个数组的首地址,长度为当前后面的len长度的数组为一个整体:
```go
func gostringnocopy(str *byte) string {
ss := stringStruct{str: unsafe.Pointer(str), len: findnull(str)}
s := *(*string)(unsafe.Pointer(&ss))
return s
}
```
从上面这段代码可以看到,string的表现形式是[]byte,string就是byte数组,并且他是一个struct
好了,现在就能够理解为什么for i的结构是这样了
#### for range
再尝试一下for range遍历吧!
```go
func main() {
str := "Hello, 世界"
for i, ch := range str {
fmt.Println(i, ch, string(ch))
}
}
```
既然专门提出来了,那么肯定不一样了,直接看结果
```json
0 72 H
1 101 e
2 108 l
3 108 l
4 111 o
5 44 ,
6 32
7 19990 世
10 30028 界
```
为什么会产生这样的结果,那么先看一下range的伪代码吧
```go
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
}
```
它是一个语法塘,底层其实是一个for i的循环,在字符串中迭代 unicode 编码。第一个返回值是rune的起始字节位置index,然后第二个是 rune 自己。(byte与rune自行了解)
虽然range是建立在for i之上的,但是它有着for i很多不具备的功能,比如遍历map,channel通道的遍历,至于为什么它这么这个牛逼,内部方法写得好是一方面,map,channel的数据结构也决定了for i的无法遍历,以后再详细介绍。
有疑问加站长微信联系(非本文作者))