友情提示:本文共有 11053 个字,阅读大概需要 23 分钟。
go语言的基础入门非常的重要,所有语言都是学的好不好要看基础牢不牢,那么该如何正确的学习go语言的呢,下面我们一起来学习吧!
第二篇:Go基础入门
2.1、第一个Go语言程序
下面我们就要正式进入Go语言的学习了。
首先还是一个传统的仪式:用程序在屏幕上输出“hello world”
步骤:
1、新建一个go项目:File–New–Progect
2、新建一个Go文件:File–New–Go File
3、在编辑区内写入下列代码:
package main
import "fmt"
func main() {
fmt.Println("hello world!")
}
1
2
3
4
5
6
7
4、右击编辑区,选择run运行代码,控制台中会得到如下结果:
代码解释:(大概有个印象就行,后面章节会详细讲解)
1、package main :
用来表示当前文件是一个可执行文件
2、import “fmt” :
import是用来导入别人已经写好的代码(代码包),“fmt”是包的名字,这样我们就可以使用别人写好的代码了,“fmt”是Go自带标准库中的一个包。
举个例子:现在你是老板,不可能什么事都自己做,所以你需要雇人工作。这里的import就相当于雇佣这个动作,而跟在import后面的"fmt"就相当于被你雇佣的人。
3、func main(){ 函数体代码.. } :
这串代码表示的是一个函数,{}内的代码叫做函数体代码,现在只需要记住“函数”、“函数体”这两个名词,后面会详细讲解。一般的函数长这样:func 函数的名字(){ 函数体代码.. },这里的func main(){ 函数体代码.. }是一个特殊的函数,固定写法,叫做程序主函数,是一个程序的入口,当你运行程序的时候,执行的就是这个程序主函数的函数体代码。
举个例子:现在有个通道,通道的一头是入口,另一头是出口,你从这入口一步步走到出口。这个通道就相当于你写的程序,而func main(){...}就相当于这个通道的入口,你在通道里一步步走的这个过程就相当于主函数的函数体代码一行行执行的过程,当你走完整个通道,那么程序也就运行结束了。
4、fmt.Println("hello world!"):
刚刚我们提到过,“fmt”是人家写好的代码,“雇佣”不是目的,目的是要使用它的功能。我们通过.功能的名字(...)来调用它的功能,这里fmt.Println("hello world!")就是在调用fmt众多功能中的Println()功能,在屏幕中输出你指定的内容。
举个例子:我们刚刚已经雇佣了一个名叫"老王"人(import "老王"),这个人呢可以干很多事情,比如洗衣做饭,但雇佣不是目的,目的是让他干活,当你有衣服要洗了,就可以通过老王.洗衣服("脏袜子")让他去做事。但如果你要有人端茶倒水,老王就不会了,这时候你就得再雇佣其他会端茶倒水的人。
##2.2、变量及其定义
###2.2.1什么是数据类型
作为牛逼的人类很容易就能区出什么是数字什么是文字,但计算机却不能,某些方面就和傻子一样,需要你清清楚楚明明白白的告诉它,1是数字,“隔壁老王”是文字,否则计算机是没法区分你存的的到底是数字还是文字。因此在每个编程语言里就会有一个叫做数据类型的东西,来对常用的数据进行明确的分类区分。你想让计算机进行数值运算,就传数字类型给它,你想让计算机处理文字,就穿字符串类型给它。在Go语言里,有26种数据类型,后面章节会由简单到复杂逐一讲解。今天只需要掌握这个概念,并且记住下面3种数据类型的表示方法:
int:整型,例如1,2,3
string:字符串类型,例如“隔壁老王”,“1”,这里需要特别强调的是,只要加上了双引号“”,都是字符串类型
bool:布尔类型,这个类型的值是固定死的,只有2个,一个是true(真),一个是false(假)。什么意思呢?比如我告诉你1>2,你会判断我说的是假的,计算机也是这样工作的,fmt.Println(1>2)得到的结果是true,反之就是false(不必深究,后面会细讲)。
###2.2.2、变量的概念
什么是变量,为什么要有变量:
引子:
现在有一个需求,需要你用fmt.println()在控制台输出下面4句话:
“隔壁油腻腻的中年大叔 来找我
隔壁油腻腻的中年大叔 说他孩子像我
隔壁油腻腻的中年大叔 问我孩子是谁的
隔壁油腻腻的中年大叔 哭了“
你会怎么做呢?是不是想到我们之前提到的fmt.Println("hello world!"),脑瓜子一拍,这很简单啊,于是你就写了:
package main
import "fmt"
func main() {
fmt.Println("隔壁油腻腻的中年大叔 来找我")
fmt.Println("隔壁油腻腻的中年大叔 说他孩子像我")
fmt.Println("隔壁油腻腻的中年大叔 问我孩子是谁的")
fmt.Println("隔壁油腻腻的中年大叔 哭了")
}
1
2
3
4
5
6
7
8
9
10
我的个神,疯了吗,你这么写是有问题的,什么问题?我问你,你这么重复的输入“隔壁油腻腻的中年大叔”累不累,烦不烦?那你该如何才能不需要每次都输入这么长呢?答案很简单,只需要把“隔壁油腻腻的中年大叔”起个名字存起来,每次要用的时候,调用这个名字就好了。
package main
import "fmt"
func main() {
var 老王 string= "隔壁油腻腻的中年大叔"
fmt.Println(老王,"说他孩子像我")
fmt.Println(老王,"说他孩子像我")
fmt.Println(老王,"问我孩子是谁的")
fmt.Println(老王,"哭了")
}
1
2
3
4
5
6
7
8
9
10
11
这样是不是就方便多了,“隔壁油腻腻的中年大叔”这么啰嗦的话只需要输入一遍就好了。老王 这个名字的作用,就是把程序中经常需要用到的值,临时存到内存里,以备后面的代码继续调用,这个名字的学名就叫做“变量”。
###2.2.3、变量的定义
说完什么是变量,为什么要有变量之后,剩下的怎么用变量就已经很简单了,每个语言有每个语言的规范,记住这些规范,就可以得心应手的使用它。go语言中,变量的定义有5种方式:
①、var 变量名1… 类型:
var a int
var b,c string
var d bool
1
2
3
这种形式下,你虽然没有指定变量的值,但Go语言会给它一个初始值:
fmt.Println(a) =====> 0
fmt.Printf("%q,%q",b,c) =====> "" "" //如果直接用Println是看不到""(空串)的,这种方法在字符串那一节会讲
fmt.Printf(d) =====> false
1
2
3
int类型的初始值:0,string类型的初始值:“”,bool类型的初始值:false。
②、var 变量名1… 类型 = 变量值1…
var a int = 123
var b,c string = "老王","小丽"
1
2
初始化变量,并且给定初始值
fmt.Println(a) =====> 123
fmt.Println(b,c) =====> "老王","小丽"
1
2
③、var 变量名1… = 变量值1…
var a = 123
var b,c = "老王",true
1
2
这种方式省略了数据类型,那这么写变量的数据类型又是什么呢?在你不指定数据类型的时候,Go语言会根据你传的变量值,自动判断类型
fmt.Println(a) =====> 123
fmt.Println(reflect.Typeof(a)) =====> int
fmt.Println(b) =====> "老王"
fmt.Println(reflect.Typeof(b)) =====> string
fmt.Println(c) =====> true
fmt.Println(reflect.Typeof(c)) =====> bool
1
2
3
4
5
6
④、变量名1…:= 变量值1…
a := 123
b,c := "老王",true
1
2
这种形式省略了var,用“:=”取代了“=”
fmt.Println(a) =====> 123
fmt.Println(reflect.Typeof(a)) =====> int
fmt.Println(b) =====> "老王"
fmt.Println(reflect.Typeof(b)) =====> string
fmt.Println(c) =====> true
fmt.Println(reflect.Typeof(c)) =====> bool
1
2
3
4
5
6
虽然这种方式是形式③的一种简便写法,但是它的使用范围受到了限制,这一点尤其重要,需要特别注意:
func main(){
a,b := 123,true
fmt.Println(a,b) =====> 123,true
}
1
2
3
4
这种形式的定义变量只能写在函数内部,不可写在函数外部,如果写在外部会直接报错:
a,b := 123,true
func main(){
fmt.Println(a,b) =====> 123,true
}
//这么写程序会报错:syntax error: non-declaration statement outside function body,意思是:没有用var关键词声明的变量超出了函数体之外
1
2
3
4
5
6
7
⑤、var (
变量名1… = 变量值1…
…
)
var(
a int= 123
b,c = "老王",true
)
1
2
3
4
强调:用“:=”这种形式定义变量只能写在函数体内,用“var”定义变量既可以写在函数体内也可以写在函数体外
###2.2.4、变量的赋值
变量的赋值操作很简单,直接使用“=”即可,变量名1… = 新值1…
var a,b,c = 11,22,33 //这里我定义变量之后,a、b、c的类型就已经固定为int类型
a,b = 44,55 //这里给a,b重新赋新值(值的类型还是int),44,55
c = "老王" //这行报错 //c的原本类型为int,但我这里给了它string类型的值,就会报错
1
2
3
强调:变量赋值的唯一注意点就是前后类型要一致
###2.2.5、变量名的命名规范
①、变量只能是字母、数字、下划线的任意组合
②、变量名不能以数字开头
③、不能使用保留关键字。【break,default,func,interface,select,case,defer,go,map,struct,chan,eles,goto,package,switch,const,fallthrough,if,range,type,continue,for,import,return,var】
建议:
④、使用驼峰体(首字母小写,后面每个独立单词的首字母大写,如,sonOfBitch、ageOfStudents)【与驼峰体相对的还有一种叫下划线体,如,son_of_bitch、age_of_students】
##2.3、常量及其定义、自增常量组
###2.3.1常量的概念
什么是常量:
常量就是恒定不变的量,和变量的概念相对。一旦定义,就只能被调用,但是不可被修改,否则程序就会报错。
为什么要有常量:
有这么一个场景,你现在和别人在联合开发一个软件,你定义了一个量,这个值在程序的运行过程中是不会改变的,而你写的程序运行的结果正确与否取决于这个量的值,所以,你并不希望被人无意间修改。这个时候常量就显得至关重要
###2.3.2常量的定义
定义变量用的是var关键字,定义常量我们用const关键字。定义常量的方法有3种:
①、const 常量名1… 数据类型 = 常量值1…
const a int = 4
const b,c string = "张三",“李四”
1
2
②、const 常量名1… = 常量值1…
常量也是可以不指定数据类型,让程序通过值来自动判断类型的
const a = 4
const b,c = "张三",“李四”
fmt.Println(reflect.Typeof(a)) ===> int
fmt.Println(reflect.Typeof(b)) ===> string
1
2
3
4
5
③、const (
常量名1… = 常量值1…
…
)
const(
a int= 123
b,c = "老王",true
)
1
2
3
4
在常量组中如果常量名既不指定常量类型也不指定常量值,那么该常量的数据类型与值和上方非空常量的数据类型与值相同
const(
a int= 123
b
c,d = "老王",true
e,f
)
fmt.Printli(reflect.Typeof(b),b) ===> int 123
fmt.Printli(reflect.Typeof(e),e) ===> string "老王"
fmt.Printli(reflect.Typeof(f),f) ===> bool true
1
2
3
4
5
6
7
8
9
10
**注意:**常量可以出现定义了但却不使用的情况,这一点和变量相反。常量一旦定义,就不能被修改。
###2.3.3自增常量组-----常量组的特殊用法
引子:
有一个需求:我需要定义4个常量,分别是a,b,c,d,他们的值分别是1,2,3,4。如何定义?是不是很简单?
const(
a = 1
b = 2
c = 3
d = 4
)
1
2
3
4
5
6
这么定义烦不烦?如果我要定义10个呢,是不是你还要写10个“=”?为了解决这个问题,就有了自增常量组的概念。
**什么是自增常量组:
常量组就是const()定义的一组常量,自增就是有规律的自动增加,不需要手动一个个赋值。
什么样的场景适合用自增常量组:
比如说,“monday,tuesday,wednesday,thursday,friday,saturday,sunday”,从星期一到星期天,我们分别可以用1,2,3,4,5,6,7这样有规律增加的数字去表示,并且他们是一个固定的值,不会随着程序的运行而变化。
如何使用自增常量组:
①、常量计数器iota
iota是一个常量计数器,顾名思义,计数器得到的是一个值,表示的是你当前常量个数,iota的初始值为0,类型默认为int,也可自行指定为其它数字类型。如下列代码:
const(
a = iota //用赋值的形式调用iota,初始值为0,类型为int
b //b的值会被自动赋值为1,类型为int
c //c的值会被自动赋值为2,类型为int
d //d的值会被自动赋值为3,类型为int
)
1
2
3
4
5
6
②、占位符_
还是刚刚那个场景,如果我要给a,b,c,d分别赋值1,2,3,4,呢,可iota又是从0开始的怎么办?
这里就引出了一个新的概念,占位符“_”,就是占着茅坑不拉shit的意思,只是占了个位置,不会被存储,也不可被调用。用法看代码:
const(
_ = iota //_占位,调用iota,初始值为0,类型为int
a //a = 1
b //b = 2
c //c = 3
d //d = 4
)
1
2
3
4
5
6
7
③、iota的中断和恢复
const(
_ = iota //_占位,调用iota,初始值为0,类型为int
a //a = 1
b //b = 2
c string = "老王" //这里iota自动赋值被中断,但计数没有停止
d //d和c的类型和值相同,string,"老王"
e = iota //iota自动赋值恢复,取计数值,5
f //f = 6
)
1
2
3
4
5
6
7
8
9
④、多个iota同时使用
可以在常量组的多常量定义中,使用多个iota,各自单独计数,前提是每行常量列数相同
const(
a,b = iota,iota //a = 0 b = 0 类型int
b,c //b = 1 c = 1
d,e //d = 2 e = 2
)
1
2
3
4
5
⑤、iota参与运算
iota可以直接参与运算:
const(
a = iota * 2 ==> 0
b ==> 2
c ==> 4
d ==> 6
)
1
2
3
4
5
6
⑤、自定义iota的类型
iota的默认类型是int,也可以使用其它数字类型,也可以使用基础类型为数字类型的自定义类型
使用其它数字类型的代码:
const(
a float32 = iota //指定为小数类型
b
)
1
2
3
4
使用基础类型为数字类型的自定义类型(自定义类型后面章节会详细讲解):
type id int8
const(
a id = iota //指定为小数类型
b
)
1
2
3
4
5
##2.4基本运算符
###2.4.1运算符的分类
计算机可以进行的运算有很多种,可不只加减乘除这么简单。在Go语言里,按照运算种类,可以分为以下几类:
①、算术运算符,②、关系运算符,③、逻辑运算符,④、位运算符,⑤赋值运算符,⑥其它运算符
###2.4.2算术运算符
以下假设A=10,B=20:
###2.4.3关系运算符
以下假设A=10,B=20:
###2.4.4逻辑运算符
以下假设A=true,B=false:
三者的优先级从高到低分别是:!,&&,||
fmt.Println(3>4 && 4>3 || 1==3 && "x" == "x" || 3>3)
>>>>>false
1
2
最好使用括号来区别优先级,其实意义与上面的一样
fmt.Println((3>4 && 4>3) || ((1==3 && "x" == "x") || 3>3))
>>>>>false
1
2
###2.4.5位运算符
学习位运算符之前我们首先得理解什么是二进制。在生活中我们用到的数字都是10进制的,就是逢10进1。二进制顾名思义就是逢2进1,所以二进制里只有0和1。
十进制转二进制:
如图:
所以10进制中10的2进制就是01010
二进制转十进制:
如图:
以下假设A = 60 , B = 13 ,A的8位二进制:00111100 ,B的8位二进制:00001101
按位与运算符&:
A: 0 0 1 1 1 1 0 0
B: 0 0 0 0 1 1 0 1
A&B: 0 0 0 0 1 1 0 0
对应位比较,如果都为1,那么按位与的结果为1,否则为0
按位或运算符|:
A: 0 0 1 1 1 1 0 0
B: 0 0 0 0 1 1 0 1
A|B: 0 0 1 1 1 1 0 1
对应位比较,只要有一个为1,那么按位或的结果为1,否则为0
按位异或运算符^:
A: 0 0 1 1 1 1 0 0
B: 0 0 0 0 1 1 0 1
A^B: 0 0 1 1 0 0 0 1
对应位比较,只要不相同就为1,否则为0
左移运算符<<
A: 0 0 1 1 1 1 0 0
A<<2: 1 1 1 1 0 0 0 0
A<<3: 1 1 1 0 0 0 0 0
各二进位全部左移n位,超出总位数就丢弃
在不丢弃的情况下,相当于10进制上乘以了2的n次方
右移运算符>>
A: 0 0 1 1 1 1 0 0
A>>2: 0 0 0 0 1 1 1 1
A>>3: 0 0 0 0 0 1 1 1
各二进位全部右移n位,超出范围就丢弃
在不丢弃的情况下,相当于10进制上除以了2的n次方
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
###2.4.6赋值运算符
如图:
2.4.4其它运算符
##2.5流程控制
###2.5.1if判断
1、if判断是什么?
if判断是用来模拟人脑判断的,当满足某种条件的时候做些事情,当不满足的时候做另外一些事情,比如渴了,就要去执行拿水杯、倒水、喝水的动作,不渴,那就执行学习的动作。
2、为什么要有if判断?
我们编程的目的是为了让计算机像人一样工作,那么人脑能做的事,就需要程序中有相应的机制去模拟,这样才能一定程度上取代人力。
3、怎么用if判断:
方式一:if
if 条件 {
代码1
....
}
1
2
3
4
例如:如果:女人的年龄>30,那么:叫阿姨。
var ageOfGirl int = 31
if ageOfGirl > 30 {
fmt.Println("阿姨好")
}
1
2
3
4
5
方式二:if-else
if 条件 {
代码1
....
}else{
代码a
....
}
1
2
3
4
5
6
7
例如:如果:女人的年龄>30,那么:叫阿姨,否则:叫小姐
var ageOfGirl int = 18
if ageOfGirl > 30 {
fmt.Println("阿姨好")
}else{
fmt.Println("小姐好")
}
1
2
3
4
5
6
7
方式三:if-else if-else
if 条件1 {
代码
...
}else if 条件2{
代码
...
}else if 条件3{
代码
...
}..... //可以写很多else if
}else{
代码
...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
例如:
如果:成绩》=90,那么:优秀,
如果:成绩》=80且<90,那么:良好,
如果:成绩》=70且<80,那么:普通
其它情况:很差
var score int = 50
if score >= 90 {
fmt.Println("优秀")
}else if score >= 80 {
fmt.Println("良好")
}else if score >= 70 {
fmt.Println("普通")
}else {
fmt.Println("很差")
}
1
2
3
4
5
6
7
8
9
10
11
方式四:if的嵌套**
if的代码体内可以再写if
if 条件1 {
代码...
if 条件x {
代码...
}else{
代码...
}
}else{
代码...
}
1
2
3
4
5
6
7
8
9
10
例如:
var ageOfGirl int = 18
var isSuccess bool = True //是否表白成功
if ageOfGirl > 30 {
fmt.Println("阿姨好")
}else{
fmt.Println("表白...")
if isSuccess {
fmt.Println("在一起...")
}else{
fmt.Println("强行在一起...")
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
方式五:判断条件之前加可执行语句,用分号隔开
if ageOfGirl := 18;ageOfGirl > 30 {
//强调:如果是定义变量,这里只能用短声明 :=
//且这里定义的变量只能在当前if相关的代码体中使用
fmt.Println("阿姨好")
}else{
fmt.Println("小姐好")
}
1
2
3
4
5
6
7
###2.5.2switch分支选择
1、switch分支选择是什么?
switch英语里是岔道的意思,表明你面临了选择,在go语言里,当满足了岔道(分支)的条件,就会去执行岔道(分支)里的代码。这个if判断很类似,满足这个条件我就执行这块代码,满足另一个条件我就执行另一块代码。
2、为什么要有switch分支选择?
既然switch分支选择功能上和if判断类似,那为什么还要有它啊?存在即合理。虽然switch分支选择也可以用if判断来实现,但是在特定的情况下,switch分支选择要比if判断更简洁。
3、怎么用switch分支选择?
方式一:
注意:
因为switch的判断就相当于“判断量==被判断量”,所以两者类型要相同,准确的讲是要能够写成“判断量==被判断量”的形式
**拓展:**
我们平时开发中尽量不要去使用break和fallthrough,break和fallthrough是用来解决历史遗留问题的,现在很多公司都在拿go去重写c的程序,在c++里,switch的一个case运行结束后,会直接去运行下一个case的体代码,除非手动在case的末尾加上break。为了兼容c++里的break功能和一个case运行完直接运行下一个case的体代码这种情况,go语言里才加入了break和fallthrough的功能
举例:
var isUgly bool = true //客户是否长得丑
switch name := "女总经理"; name {
case "男总经理","女总经理":
fmt.Println("总经理好")
case "预约访客":
if isUgly {
break //长得丑就直接终止程序
}else{
fmt.Println("你微信号多少")
}
fmt.Println("你好")
default:
fmt.Println("出门右转")
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
方式二:
举例:
var studentFather string = "校长"
switch score := 82; {
case score>=90,studentFather == "校长" :![在这里插入图片描述](https://img-blog.csdnimg.cn/20191224100919765.png)
fmt.Println("优秀")
case score>=80 :
fmt.Println("良好")
case score>=70 :
fmt.Println("一般")
default :
fmt.Println("很差")
}
1
2
3
4
5
6
7
8
9
10
11
12
13
###2.5.3 for循环
1、什么是循环:
循环很好理解,就是重复的做一件事,在计算机里,就是重复的执行一段代码。
2、为什么要有循环:
我们反复提到过,编程的目的是让计算机能够像人一样去工作。生活中,我们会经常循环的做一件事,比如说,“今天吃饭,明天吃饭,后天也要吃饭”,“服务员今天提供服务,明天后天也同样要提供相同的服务”。既然人需要循环的做某件事,那计算机同样需要有相应的机制来循环的执行代码。
3、怎么用for循环:
####2.5.3.1for循环基本形式
for 初始条件;循环条件;追加语句{
循环体代码...
}
1
2
3
详解:
for循环开始时会首先执行一次“初始条件”,然后接着判断“循环条件”是否为true,如果是true,那就开始执行“循环体代码”,每一次循环结束都会执行一次“追加语句”,然后继续判断“循环条件”,fasle就结束循环。
正常情况下,我们会在“初始条件”里写一个变量声明,通过对这个变量的判断,以及赋值来控制循环的次数。如:
for i := 0; i < 3; i++ {
fmt.Println(i)
}
1
2
3
每次循环后变量i都会加1,直到不满足i<3这个循环条件,如此,循环就被限制成了3次。
省略形式:
初始语句,循环条件和追加条件都可以被省略,但“;”要保留,如下:
1、省略初始语句。
这没什么好说的,初始语句就是在for循环第一次执行的时候有且只只会执行一次。省略了它,写在for循环外面也一样。但需要注意的是,如果变量在初始化语句中定义,那么它就只能在for中被使用。
var i int = 0
for ; i < 3; i++{
.......
}
1
2
3
4
5
2、省略追加语句。
这也没什么好说的,追加语句就是在每次循环结束的时候会执行的语句。省略了它,就写在for循环的循环体代码内,效果也一样。它的省略是为了让循环更加灵活,我们可以把“i++”写在循环体的任意一行,也可以通过判断对它进行逻辑修饰。
var isAdd2 = true
for i := 0; i < 3; {
if isAdd2{
i += 2
}else{
i++
}
}
1
2
3
4
5
6
7
8
9
同时省略初始语句和追加语句时,“;”可以不写,如:
var i int = 0
var isAdd2 = true
for i < 3 {
if isAdd2{
i += 2
}else{
i++
}
}
1
2
3
4
5
6
7
8
9
10
3、省略循环条件。
当循环条件被省略的时候,for循环运行一次之后进行循环条件判断的时候,会把循环条件当成true。换句话说,就是会一直循环。如:
for i:=0; ; i++{
fmt.Println(i)
}
//相当于:
for i:=0; true; i++{
fmt.Println(i)
}
1
2
3
4
5
6
7
8
for后面的语句都省略的时候,“;”也可以不写:
for {
i++
fmt.Println(i)
}
1
2
3
4
####2.5.3.2for循环的嵌套
for循环里嵌套了一个或者多个for循环,如下:
for i:=0; i<3; i++ {
fmt.Println("第一层:",i)
for j:=0; j<3; j++ {
fmt.Println("第二层:",j)
}
}
1
2
3
4
5
6
####2.5.3.4for循环的终止
1、变量开关
for tag:=true; tag;{
.....
for tag {
....
tag = false
}
}
1
2
3
4
5
6
7
我们把变量开关放在循环条件里,通过对变量开关的控制(赋值为fasle),来跳出循环。
2、continue
for i:=0; i<10; i++{
if i == 5 {
continue
}
fmt.Println(i)
}
1
2
3
4
5
6
当前循环一旦碰到continue,不管循环体里剩下多少代码没有执行,都会直接跳过,开始下一次循环
3、break
for i:=0; i<3; i++{
fmt.Println("第一层:",i)
for j:=0; j<10; j++{
fmt.Println("第二层:",j)
if j==1 {
break
}
}
}
1
2
3
4
5
6
7
8
9
结果:
第一层: 0
第二层: 0
第二层: 1
第一层: 1
第二层: 0
第二层: 1
1
2
3
4
5
6
说明:
如果没有break,那么第二层循环应该执行10次,但我在j=1(第二层循环执行到第二次)的时候加上了break,那么就直接跳出了第二层循环,剩下的8次都不会再执行
###2.5.4标签
1、什么是标签:
生活中标签是用来附在某样东西上,并给它做标记的。go语言中,标签是用来给代码做标记的,会记录住代码的在程序中的位置。
2、为什么要有标签:
标记不是目的,目的是使用。我们记录位置是为了干什么呀?当然是为了快速的找到被标记的代码,方便进行相应的操作。
3、怎么用标签:
标签的格式如下:
标签名1:
for i := 0; i < 5; i++ {
代码...
}
标签名2:
switch {
代码...
}
标签名3:
fmt.Println("今天天气不错")
1
2
3
4
5
6
7
8
9
10
11
12
说明:
1、为了区分标签和变量,通常标签名我们会用大写字母加数字来表示。
2、创建了标签就一定要使用,不然会引发错误。
####2.5.4.1break + 标签
我们在for循环里讲到过break,for循环里单独写break是用来跳出本层循环的。如:
for {
for i:=0; ; i++ {
if i == 2 {
fmt.Println(i)
break
}
}
}
1
2
3
4
5
6
7
8
运行的结果是控制台无限打印2,原因是这里的break只是跳出了里层循环,而最外层的循环并没有被终止。
那现在我就想满足条件时,终止所有循环,怎么办?我们改变它的循环条件不就完了嘛,之前是不是学过一个变量开关的方法啊?如下:
for tag:=true; tag; {
for i:=0; tag; i++ {
if i==2 {
fmt.Println(i)
tag = false
}
}
}
1
2
3
4
5
6
7
8
还有其它方法吗?当然有,就是我们下面要说的break + 标签。如下:
LABEL1:
for {
for i:=0; ; i++ {
if i == 2 {
fmt.Println(i)
break LABEL1
}
}
}
1
2
3
4
5
6
7
8
9
我们用LABEL1来标记最外层循环,然后用break LABEL1来指定要跳出的循环,这里跳出的是最外层循环。
当然也可以用标签去标记内层循环,如:
for {
LABEL1:
for {
for i:=0; ; i++ {
if i == 2 {
fmt.Println(i)
break LABEL1
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
####2.5.4.2continue + 标签
continue + 标签,用于终止指定循环的本次循环并继续下一次循环。用法和break一样,只是关键字不同。如:
LABEL1:
for i:=0; i<3; i++ {
for j:=0; j<3; j++ {
continue LABEL1
fmt.Println("我是内层循环,j=",j)
}
fmt.Println("我是外层,i=",i)
}
1
2
3
4
5
6
7
8
####2.5.4.3 goto + 标签
代码都是从上而下一行行执行的,而goto + 标签,可以强行跳转到函数体内指定代码,并继续向下执行。
在一般的开发中,“goto LABEL”能不用就不用,除非是遇到的问题再也没有其它更好的办法可以解决。因为“goto LABEL”牺牲的是代码可读性和可维护性。
func main(){
for i:=0; i<3; i++ {
fmt.Println(i)
if i>1 {
goto EXIT
}
}
EXIT:
fmt.Println("exit....")
}
1
2
3
4
5
6
7
8
9
10
11
注意:
1、goto语句仅适用于函数内部跳转,不可跳转到其它函数。
func text1() {
LABEL1: //报错 label LABEL1 defined and not used
fmt.Println("我是text1")
}
func main() {
goto LABEL1 //报错 label LABEL1 not defined
}
1
2
3
4
5
6
7
8
这和函数作用域有关,我们在函数这一章中会具体讲解
2、goto语句不能跳过变量声明语句。
goto LABEL1
//报错 goto LABEL1 jumps over declaration of a
//goto LABEL1 跳过了a的声明
var a int= 111
LABEL1:
fmt.Println("测试......")
1
2
3
4
5
6
本文如果对你有帮助,请点赞收藏《go语言入门教程02 Go基础入门》,同时在此感谢原作者。