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])
}
}