Go 循环 (for)

循环类型

for:

for a := 0; a < 10; a ++{
		fmt.Println(a)
	}

在执行结束后 a == 10

while:

a := 0
for a < 10{
	fmt.Println(a)
	a ++
}

while true:

a := 0
for {
	fmt.Println(a)
	a ++
}

label

label 用于标记跳转的位置,可用于 break continue goto
label 名 + ':' 组成一个 label
示例:
未使用 label,continue 只能跳过内层循环

package main

import "fmt"

func main() {
	for i := 0; i < 3; i ++ {
		for j := 0; j <= 3; j ++ {
			if j == i{
				continue
			}
			fmt.Println(i, j)
		}
	}
}

使用 label,continue 可以跳过外层循环

package main

import "fmt"

func main() {
	LABEL:
	for i := 0; i < 3; i ++ {
		for j := 0; j <= 3; j ++ {
			if j == i{
				continue LABEL
			}
			fmt.Println(i, j)
		}
	}
}

goto:

不建议使用 goto

package main

import "fmt"

func main() {
	var i = 1
	LOOP1: 
		for i < 10 {
			fmt.Println(i)
			i ++
			if i % 2 == 0 {
				goto LOOP2
			}
		}
	LOOP2: 
		for i < 10 {
			fmt.Println("even:", i)
			i ++
			goto LOOP1
		}
}

输出结果:

1
even: 2
3
even: 4
5
even: 6
7
even: 8
9

当 i 为奇数时,在打印出 i 的值之后,i 变为偶数,从 LOOP1 跳入 LOOP2,在 LOOP2 打印出 i 的值后,i 变为奇数,跳入 LOOP1

for range

for range 用来循环数组、切片等
示例:

func main() {
	a := "hello world"
	for i, v := range a {
		fmt.Printf("%d, %c\n", i, v)
	}
}

输出结果:

0, h
1, e
2, l
3, l
4, o
5,  
6, w
7, o
8, r
9, l
10, d

i 为索引,v 为值

只读

由于 for range 遍历的值都只是原来值的复制,所以不能通过 for range 修改原来的值,所以 for range 获得的值可以看作是只读的
示例:

func main() {
	a := []int{1, 2, 3}
	for i, v := range a {
		fmt.Printf("v: %v, %p, i: %v, %p, a[i]: %v, %p\n", v, &v, i, &i, a[i], &a[i])
	}
}

输出结果:

v: 1, 0xc00001a090, i: 0, 0xc00001a088, a[i]: 1, 0xc000014140
v: 2, 0xc00001a090, i: 1, 0xc00001a088, a[i]: 2, 0xc000014148
v: 3, 0xc00001a090, i: 2, 0xc00001a088, a[i]: 3, 0xc000014150

可以看到在 for range 循环中,获取到的值只是原来的一个复制,并没有指向原来的地址,每次循环都会修改这个值

优化

由于 for range 需要获取值的复制,因此性能上会比一般的 for 循环差一些,可以通过只获取索引,然后通过索引获取值的方式提高效率
示例:

func main() {
	a := "hello world"
	for i, _ := range a {
		fmt.Printf("%d, %c\n", i, a[i])
	}
}

posted on 2019-12-18 14:26  doubtful  阅读(678)  评论(0编辑  收藏  举报

导航