1. for语法
Go中仅有for一种循环语句,没有while和do while这种语法。但是常用方式都能实现。
三种常用方式如下:
for i := 0; i < 10; i++ {
}
for i < 10 { // 类似于while(i < 10) {}
}
for { // 类似于while(true) {}
break
}
对于第一种方式,初始化语句i := 0仅被执行一次,初始化完成后,将检查条件语句i<10,若为true,则执行循环体,执行完循环体后,再执行后面的赋值语句i++,接着检查条件语句;若检查条件语句结果为false,则跳出循环。
2. break & continue
break语句常用于中断for循环的执行,而continue用于中断当前for循环的,立即进入下一轮循环。
func main() {
for i := 0; i < 5; i++ {
if i == 2 { // 当 i == 2时,跳出整个循环
break
}
fmt.Printf(" %d", i)
}
fmt.Println()
for i := 0; i < 5; i++ {
if i == 2 { // 当i == 2时,跳出当前轮循环
continue
}
fmt.Printf(" %d", i)
}
}
执行结果如下:
0 1
0 1 3 4
3. for…range
for…range可完成数据迭代,支持字符串、数组、字典、切片通道类型。
其语法如下:
for index, value := range data { }
举一个例子,定义一个string切片,通过for…range遍历并打印切片内容:
func main() {
data := []string{"a", "b", "c"}
for index, value := range data {
fmt.Println("index:", index, " value:", value)
}
}
执行结果:
index: 0 value: a
index: 1 value: b
index: 2 value: c
当然range可以返回单值,或者用"_"忽略。
func main() {
data := []string{"a", "b", "c"}
for index := range data { // 忽略value
fmt.Println("index:", index)
}
for _, value := range data { // 忽略index
fmt.Println("value:", value)
}
}
4. 更多
4.1 标签
go语法中支持标签指定目标层级。
假设我们有一个需求,在二重循环中想要终止程序,一般可以定义一个flag,在外层循环中通过判断flag来决定循环是否终止。
func main() {
for {
flag := false // 定义一个bool变量
for {
flag = true
break
}
if flag {
break
}
}
}
我们也可以使用标签达到同样的效果:
func main() {
label: // 定义一个label标签
for {
for {
break label // 终止外层循环
}
}
}
for…rangefor…range在迭代中做的是值拷贝,举一个例子如下:
func main() {
data := [3]int{10, 20, 30}
for i, v := range data { // 将data复制一份
if i == 0 {
data[0] += 100
data[1] += 200
data[2] += 300
}
fmt.Printf("i:%d, v:%d, data[%d]:%d\n", i, v, i, data[i])
}
}
i:0, v:10, data[0]:110
i:1, v:20, data[1]:220
i:2, v:30, data[2]:330
for…range会将data复制一份,每次循环会从复制品种取出一个值赋给变量v,当i==0时,data中元素即使被改变,也不影响v的结果。再看下面这个例子,和你预期的结果一样吗?
func main() {
m := make(map[string]*student, 10)
stus := []student{
{name: "tom", age: 18},
{name: "Alice", age: 25},
{name: "lucy", age: 20},
}
for _, stu := range stus {
fmt.Printf("%p\n", &stu)
m[stu.name] = &stu
}
for k, v := range m {
fmt.Println(k, "=>", v.name)
}
}
执行结果如下:
0xc000008078
0xc000008078
0xc000008078
Alice => lucy
tom => lucy
lucy => lucy
出现这样的结果的原因就是range 在迭代中会做值拷贝,会把整个结构体拷贝给当前循环空间,stu变量会被循环赋值,而stu 内存地址不改变,所以输出的三个地址是一样的.
三次拷贝的内容会在stu地址上覆盖,因此最后map中 3 个值都指向的是stu地址。
关注我的公众号
Golang猫
获取更多文章和资源。