Go基础:for循环

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猫获取更多文章和资源。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值