GO语言学习
四、GO的条件语句:
1、if:语句
①、单分支:
if 条件{
代码块
}
②、多分支
if 条件{
代码块
}else if 条件{
...
}
2、switch:语句
switch 语句用于基于不同条件执行不同动作。
注意:
①、在这里根据条件语句来执行一条case的选择项(不想java是从选择想开始向下执行),
如果case执行的代码一样时可以将选着条件放在同一个case后(用逗号分隔)
②、switch 的后面还可以死不用写条件语句 ,而是将判断直接写在case后面
五、GO的循环语句:
1、for循环
for a ; a< n; a++{
代码块
}
for循环里面还可以在写for循环,组合成for的循环嵌套
2、死循环:for语句不写条件
注意:
①、break:跳出循环
②、continue:跳出本次循环
3、goto语句:将控制转移到被标记的语句。
func main(){
pmt.Print(" 1")
goto TOTHREE
TOTWO:
pmt.Print(" 2")
return //结束函数
TOTHREE:
pmt.Print(" 3")
goto TOTWO
}
以上代码则是结果: 1 3 2
六、GO的函数
函数用于封装一段代码块,以便用于重复调用
1、函数声明高数了编译器函数的名称,参数和返回值类型(不是必需的)
①、无法返回值如:
func main(){ //主函数执行
toRangeName("张三","李四","王二") //调用函数
}
func toRangeName(names ... string){ //不定长度参数:类型为切片,是一个数组容器(动态数组,相当于list)
for i,name:= range names{ //遍历names
pmt.Printf("name" + i) //如果:下标i不使用用_,如:for _,name := range names{...}
}
pmt.Printf(names) //打印结果: [张三 李四 王二]
}
注意:不定长的参数要放在参数列表的末尾如func (A int ,names...string)(){}
②、有返回值如:
func main(){
sum := tosum(10,12) //调用函数
pmt.Printf(sum)
}
func tosum(a, b int)(sum int){ //sum是返回的值的预定义名称,在这里写了之后在return 的后面将不用写了如下:
sum := a + b
return
}
注意:返回值有几个,在函数return的后面就有几个
2、匿名函数:没有函数名,是有封装的必要,但没有复用的价值;
1、典型的应用的场景:延时执行
defer func(){ //在函数结束之前执行(在return 之前)如果有多个代码块被defer修饰时,修饰代码将会按defer修饰顺序逆序执行
代码块
}()
2、并发执行
go func(){ //子线程 与主线程并发执行(跟主线程一起执行)
代码块
}()
3、带参数和返回值的匿名函数
func main(){
pmt.Printf(1)
func (name string) (name string){
name = name + "1"
pmt.Printf(name)
}("张三")
}
4、闭包函数:返回函数的函数
func main() {
add_func := add(1,2)
fmt.Println(add_func())
fmt.Println(add_func())
fmt.Println(add_func())
}
// 闭包使用方法
func add(x1, x2 int) func()(int,int) {
i := 0
return func() (int,int){
i++
return i,x1+x2
}
}
5、递归:就是自己 调用自己(一路递)
注意:递归一定要有终止条件,否则就会无限死循环
好处:在很多的情况下,队规的逻辑相比于循环要好理解,易于开发和维护
不足:执行的效率远逊于循环
七、GO语言的复合类型
1、指针(pointer):存的是地址
var a int = 123
fmt.Printf("a的地址是%p\n",&a) //&a对值取地址 类型是int,%p获取的是a的16进制地址
b := &a //b是一个int的地址
*b = 456 // *a对地址取值,将a的值变成456
fmt.Printf("*a的值",*b)
//定义整型指针
var xPtr *intfmt.Println("xPrtr=",xPtr) //<nil>默认值
例如:
对值取地址:namePtr := &name ->name的地址
对地址取值:*namePtr ->name的值
指向指针的指针:npp := &namePtr ->namePtr的地址
2、数组(array):定长的元素,存储同一类型的数据
数组声明方式:
①var array [5]int = [5]int{1,2,3,4,5}
②var array = [5]int{1,2,3} //元素个数可以少,还能不写元素只写一个大括号,但不能多
③ array := [5]int{} //没有的自动默认为0
④ array := [...]int{1,2,3,2,5,6,7} //定义元素个数时可以用三个点,表示自动识别个数
打印时直接用数组名进行打印(跟java不同的是java直接用数组名打印的话,只会打印数组的地址)
获取数组长度:
len.(array) //len是内嵌函数(内建函数),即不需要包名点直接写len(数组名)
根据下标获取元素:
array[0] //获取数组的第一个元素
array[0] = 23 //给第一个元素赋值
a := 20 + 10
array[a] //当a的大于数组的元素个数,可以编译,但运行时错误出现:index otu of range //下标越界
注意:如果直接写array[50]编译不通过,会直接检测出越界异常(即50会显示红色)
遍历数组:
① for i :=0; i < len.(array); i++{ //array数组名
fmt.Printf("第%d个元素是%d\n",i,array[i])
}
② for index ,value := range array{ //index是下标,value是指
fmt.Printf("第%d个元素是%d\n",index,value)
}
3、切片(slice):能动态扩容的元素,根据下标\序号访问容器
①用切片从数组中截取元素
array[start:end] 从数组身上截取下标为[start,end)的片段,形成切片
start:表示开始的下标,不写则是默认从头开始切
end:表示结束的下标(本身不包含),不写则迷人截取到末尾
var array = [10]int{10,12,1,5,3,2,15,21,1,6}
//含头不含尾,从0项到底9项(也就是从第一个元素到第十个元素)
slice :=array[0:10] //[0,10)这里相当于数组的下标
//array的类型是[10]int,值是[10 12 1 5 3 2 15 21 1 6]
fmt.Printf("array的类型是%T,值是%v\n",array,array)
//slice的类型是[]int,值是[10 12 1 5 3 2 15 21 1 6]
//切片是不定长的,可以动态扩容的数组
fmt.Printf("slice的类型是%T,值是%v\n",slice,slice)
②给切片动态追加元素
var slice[]int = []int{}//初始化切片,没有元素
fmt.Printf("slice的长度%d,值是%v\n",len(slice),slice)
//结果:slice的长度0,值是[]
slice = append(slice,0) //给slice追加元素0
fmt.Printf("slice的长度%d,值是%v\n",len(slice),slice)
//结果:slice的长度1,值是[0]
注意:append追击元素时可以同时加多个元素
slice = append(slice,1,2,3,4,5)
fmt.Printf("slice的长度%d,值是%v\n",len(slice),slice)
//结果:slice的长度6,值是[0 1 2 3 4 5]
③切片的遍历方式与数组的一样
④切片中加插入另一个切片
//定义两个切片
slice := []int{1,2,3}
slice2 := []int{4,5,6,7}
方法一:for循环的方式一个一个的添加
for _, value :=range slice2{
slice = append(slice,value)
}
方法二:直接在slice的后面直接加一个切片slice2
slice = append(slice,slice2...)
⑤切片容量
用var 声明切片的时候切片的长度和容量是相等的
切片的另一种创建方式:
//slice := make([]int, 3) //类型是:[]int 长度:3
slice := make([]int, 3, 5) //类型是:[]int 长度:3 容量:5
fmt.Println(len(slice),cap(slice)) //cap(slice)切片的容量
使用make的方式创建指定长度的切片和容量,容量不写则默认与长相同
在后续的扩容(容量不够时)是在内存有多的话将会翻一倍,不够多就两个两个的递增
slice := make([]int,1)
fmt.Println("长度等于=",len(slice),"容量等于=",cap(slice),"值=",slice) //自不写默认为0
//结果:长度等于= 1 容量等于= 1 值= [0]
slice = append(slice,1,2)
fmt.Println("长度等于=",len(slice),"容量等于=",cap(slice),"值=",slice)
//结果:长度等于= 3 容量等于= 4 值= [0 1 2]
注意:
var array = [5]int{0,1,2,3,4}
slice1 := array[:]
slice2 := slice1[:]
这时array,slice1,slice2的元素地址相同,改变array的元素值时,其他两个也发生改变
若其中一个发生扩容时会将所有的元素重新拷贝到一片新的连续内存中
这时地址就会发生改变了
4、映射:存储键值对数据,根据键访问值
①键值对的定义:定义string为键int为值的映射
var scoreMap map[string]int = map[string]int{}
var scoreMap = map[string]int{}
scoreMap := map[string]int{}
scoreMap := make(map[string]int)
②校验访问键值
score , ok := scoreMap[键值]
//score为对应键的int值,Ok表示是否有该键,有为true,没有为false
5、函数:复用自己的包(GOPATH)外部类库的检索目录
6、结构体 :是由一系列具有相同类型或不同类型的数据构成的数据集合。
一项记录,比如保存图书馆的书籍记录,
八、类库的复用
1、用自己的类包:将自己写的类放到GOPATH中
注意:在这时要将自己的类库包放在src的目录下并将src文件放下GOPATH的包目录下