go语言的基础入门非常的重要,所有语言都是学的好不好要看基础牢不牢,那么该如何正确的学习go语言的呢,下面我们一起来学习吧!
第二篇:Go基础入门
2.1、第一个Go语言程序
下面我们就要正式进入Go语言的学习了。
首先还是一个传统的仪式:用程序在屏幕上输出“helloworld”
步骤:
1、新建一个go项目:File–New–Progect
2、新建一个Go文件:File–New–GoFile
3、在编辑区内写入下列代码:
packagemain
importfmt
funcmain(){
fmt.Println(helloworld!)
}
1
2
3
4
5
6
7
4、右击编辑区,选择run运行代码,控制台中会得到如下结果:
代码解释:(大概有个印象就行,后面章节会详细讲解)
1、packagemain:
用来表示当前文件是一个可执行文件
2、import“fmt”:
import是用来导入别人已经写好的代码(代码包),“fmt”是包的名字,这样我们就可以使用别人写好的代码了,“fmt”是Go自带标准库中的一个包。
举个例子:现在你是老板,不可能什么事都自己做,所以你需要雇人工作。这里的import就相当于雇佣这个动作,而跟在import后面的fmt就相当于被你雇佣的人。
3、funcmain(){函数体代码..}:
这串代码表示的是一个函数,{}内的代码叫做函数体代码,现在只需要记住“函数”、“函数体”这两个名词,后面会详细讲解。一般的函数长这样:func函数的名字(){函数体代码..},这里的funcmain(){函数体代码..}是一个特殊的函数,固定写法,叫做程序主函数,是一个程序的入口,当你运行程序的时候,执行的就是这个程序主函数的函数体代码。
举个例子:现在有个通道,通道的一头是入口,另一头是出口,你从这入口一步步走到出口。这个通道就相当于你写的程序,而funcmain(){...}就相当于这个通道的入口,你在通道里一步步走的这个过程就相当于主函数的函数体代码一行行执行的过程,当你走完整个通道,那么程序也就运行结束了。
4、fmt.Println(helloworld!):
刚刚我们提到过,“fmt”是人家写好的代码,“雇佣”不是目的,目的是要使用它的功能。我们通过.功能的名字(...)来调用它的功能,这里fmt.Println(helloworld!)就是在调用fmt众多功能中的Println()功能,在屏幕中输出你指定的内容。
举个例子:我们刚刚已经雇佣了一个名叫老王人(import老王),这个人呢可以干很多事情,比如洗衣做饭,但雇佣不是目的,目的是让他干活,当你有衣服要洗了,就可以通过老王.洗衣服(脏袜子)让他去做事。但如果你要有人端茶倒水,老王就不会了,这时候你就得再雇佣其他会端茶倒水的人。
##2.2、变量及其定义
###2.2.1什么是数据类型
作为牛逼的人类很容易就能区出什么是数字什么是文字,但计算机却不能,某些方面就和傻子一样,需要你清清楚楚明明白白的告诉它,1是数字,“隔壁老王”是文字,否则计算机是没法区分你存的的到底是数字还是文字。因此在每个编程语言里就会有一个叫做数据类型的东西,来对常用的数据进行明确的分类区分。你想让计算机进行数值运算,就传数字类型给它,你想让计算机处理文字,就穿字符串类型给它。在Go语言里,有26种数据类型,后面章节会由简单到复杂逐一讲解。今天只需要掌握这个概念,并且记住下面3种数据类型的表示方法:
int:整型,例如1,2,3
string:字符串类型,例如“隔壁老王”,“1”,这里需要特别强调的是,只要加上了双引号“”,都是字符串类型
bool:布尔类型,这个类型的值是固定死的,只有2个,一个是true(真),一个是false(假)。什么意思呢?比如我告诉你12,你会判断我说的是假的,计算机也是这样工作的,fmt.Println(12)得到的结果是true,反之就是false(不必深究,后面会细讲)。
###2.2.2、变量的概念
什么是变量,为什么要有变量:
引子:
现在有一个需求,需要你用fmt.println()在控制台输出下面4句话:
“隔壁油腻腻的中年大叔来找我
隔壁油腻腻的中年大叔说他孩子像我
隔壁油腻腻的中年大叔问我孩子是谁的
隔壁油腻腻的中年大叔哭了“
你会怎么做呢?是不是想到我们之前提到的fmt.Println(helloworld!),脑瓜子一拍,这很简单啊,于是你就写了:
packagemain
importfmt
funcmain(){
fmt.Println(隔壁油腻腻的中年大叔来找我)
fmt.Println(隔壁油腻腻的中年大叔说他孩子像我)
fmt.Println(隔壁油腻腻的中年大叔问我孩子是谁的)
fmt.Println(隔壁油腻腻的中年大叔哭了)
}
1
2
3
4
5
6
7
8
9
10
我的个神,疯了吗,你这么写是有问题的,什么问题?我问你,你这么重复的输入“隔壁油腻腻的中年大叔”累不累,烦不烦?那你该如何才能不需要每次都输入这么长呢?答案很简单,只需要把“隔壁油腻腻的中年大叔”起个名字存起来,每次要用的时候,调用这个名字就好了。
packagemain
importfmt
funcmain(){
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…类型:
varaint
varb,cstring
vardbool
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…
varaint=
varb,cstring=老王,小丽
1
2
初始化变量,并且给定初始值
fmt.Println(a)=====
fmt.Println(b,c)=====老王,小丽
1
2
③、var变量名1…=变量值1…
vara=
varb,c=老王,true
1
2
这种方式省略了数据类型,那这么写变量的数据类型又是什么呢?在你不指定数据类型的时候,Go语言会根据你传的变量值,自动判断类型
fmt.Println(a)=====
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:=
b,c:=老王,true
1
2
这种形式省略了var,用“:=”取代了“=”
fmt.Println(a)=====
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
虽然这种方式是形式③的一种简便写法,但是它的使用范围受到了限制,这一点尤其重要,需要特别注意:
funcmain(){
a,b:=,true
fmt.Println(a,b)=====,true
}
1
2
3
4
这种形式的定义变量只能写在函数内部,不可写在函数外部,如果写在外部会直接报错:
a,b:=,true
funcmain(){
fmt.Println(a,b)=====,true
}
//这么写程序会报错:syntaxerror:non-declarationstatementoutsidefunctionbody,意思是:没有用var关键词声明的变量超出了函数体之外
1
2
3
4
5
6
7
⑤、var(
变量名1…=变量值1…
…
)
var(
aint=
b,c=老王,true
)
1
2
3
4
强调:用“:=”这种形式定义变量只能写在函数体内,用“var”定义变量既可以写在函数体内也可以写在函数体外
###2.2.4、变量的赋值
变量的赋值操作很简单,直接使用“=”即可,变量名1…=新值1…
vara,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、变量名的命名规范
①、变量只能是字母、数字、下划线的任意组合
②、变量名不能以数字开头
③、不能使用保留关键字。
建议:
④、使用驼峰体(首字母小写,后面每个独立单词的首字母大写,如,sonOfBitch、ageOfStudents)
##2.3、常量及其定义、自增常量组
###2.3.1常量的概念
什么是常量:
常量就是恒定不变的量,和变量的概念相对。一旦定义,就只能被调用,但是不可被修改,否则程序就会报错。
为什么要有常量:
有这么一个场景,你现在和别人在联合开发一个软件,你定义了一个量,这个值在程序的运行过程中是不会改变的,而你写的程序运行的结果正确与否取决于这个量的值,所以,你并不希望被人无意间修改。这个时候常量就显得至关重要
###2.3.2常量的定义
定义变量用的是var关键字,定义常量我们用const关键字。定义常量的方法有3种:
①、const常量名1…数据类型=常量值1…
constaint=4
constb,cstring=张三,“李四”
1
2
②、const常量名1…=常量值1…
常量也是可以不指定数据类型,让程序通过值来自动判断类型的
consta=4
constb,c=张三,“李四”
fmt.Println(reflect.Typeof(a))===int
fmt.Println(reflect.Typeof(b))===string
1
2
3
4
5
③、const(
常量名1…=常量值1…
…
)
const(
aint=
b,c=老王,true
)
1
2
3
4
在常量组中如果常量名既不指定常量类型也不指定常量值,那么该常量的数据类型与值和上方非空常量的数据类型与值相同
const(
aint=
b
c,d=老王,true
e,f
)
fmt.Printli(reflect.Typeof(b),b)===int
fmt.Printli(reflect.Typeof(e),e)===string老王
fmt.Printli(reflect.Typeof(f),f)===booltrue
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
cstring=老王//这里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=0b=0类型int
b,c//b=1c=1
d,e//d=2e=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(
afloat32=iota//指定为小数类型
b
)
1
2
3
4
使用基础类型为数字类型的自定义类型(自定义类型后面章节会详细讲解):
typeidint8
const(
aid=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(
1==3x==x
33)
false
1
2
最好使用括号来区别优先级,其实意义与上面的一样
fmt.Println(()
((1==3x==x)
33))
false
1
2
###2.4.5位运算符
学习位运算符之前我们首先得理解什么是二进制。在生活中我们用到的数字都是10进制的,就是逢10进1。二进制顾名思义就是逢2进1,所以二进制里只有0和1。
十进制转二进制:
如图:
所以10进制中10的2进制就是
二进制转十进制:
如图:
以下假设A=60,B=13,A的8位二进制:,B的8位二进制:
按位与运算符:
A:
B:
AB:
对应位比较,如果都为1,那么按位与的结果为1,否则为0
按位或运算符
:
A:
B:
A
B:
对应位比较,只要有一个为1,那么按位或的结果为1,否则为0
按位异或运算符^:
A:
B:
A^B:
对应位比较,只要不相同就为1,否则为0
左移运算符
A:
A2:
A3:
各二进位全部左移n位,超出总位数就丢弃
在不丢弃的情况下,相当于10进制上乘以了2的n次方
右移运算符
A:
A2:
A3:
各二进位全部右移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,那么:叫阿姨。
varageOfGirlint=31
ifageOfGirl30{
fmt.Println(阿姨好)
}
1
2
3
4
5
方式二:if-else
if条件{
代码1
....
}else{
代码a
....
}
1
2
3
4
5
6
7
例如:如果:女人的年龄30,那么:叫阿姨,否则:叫小姐
varageOfGirlint=18
ifageOfGirl30{
fmt.Println(阿姨好)
}else{
fmt.Println(小姐好)
}
1
2
3
4
5
6
7
方式三:if-elseif-else
if条件1{
代码
...
}elseif条件2{
代码
...
}elseif条件3{
代码
...
}.....//可以写很多elseif
}else{
代码
...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
例如:
如果:成绩》=90,那么:优秀,
如果:成绩》=80且90,那么:良好,
如果:成绩》=70且80,那么:普通
其它情况:很差
varscoreint=50
ifscore=90{
fmt.Println(优秀)
}elseifscore=80{
fmt.Println(良好)
}elseifscore=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
例如:
varageOfGirlint=18
varisSuccessbool=True//是否表白成功
ifageOfGirl30{
fmt.Println(阿姨好)
}else{
fmt.Println(表白...)
ifisSuccess{
fmt.Println(在一起...)
}else{
fmt.Println(强行在一起...)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
方式五:判断条件之前加可执行语句,用分号隔开
ifageOfGirl:=18;ageOfGirl30{
//强调:如果是定义变量,这里只能用短声明:=
//且这里定义的变量只能在当前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的功能
举例:
varisUglybool=true//客户是否长得丑
switchname:=女总经理;name{
case男总经理,女总经理:
fmt.Println(总经理好)
case预约访客:
ifisUgly{
break//长得丑就直接终止程序
}else{
fmt.Println(你