一.流程控制
1.选择结构
if-else:
package main import ( "io/ioutil" "fmt" ) func main(){ const filename="abc.txt" //读文件 content,err :=ioutil.ReadFile(filename) if err !=nil{ fmt.Println(err) }else{ fmt.Printf("%s ",content) } //if也支持如下语法 if content,err :=ioutil.ReadFile(filename);err !=nil{ fmt.Println(err) }else{ fmt.Printf("%s ",content) } }
switch:
package main import "fmt" //传入成绩,返回评分等级 func grade(score int) string { //定义字符串 g := "" //go为switch每一句都加了break switch { case score < 0 || score > 100: g = "输入错误" case score < 60: g = "不及格" case score < 80: g = "良" case score < 90: g = "优" case score <= 100: g = "GOOD" } //default: "hahah" return g } func main(){ fmt.Println( grade(0), grade(61), grade(75), grade(86), grade(86), grade(101), ) }
2.循环结构
for:
package main import ( "fmt" "time" ) //死循环 func for1(){ for { fmt.Println("波多野结衣的奶子大大的") //睡一秒 time.Sleep(1*time.Second) } } //有次数的循环 func for2(){ for i :=1;i<10;i++ { fmt.Println("波多野结衣可以让我幸福死") } } //有次数的循环加控制 func for3(){ for i :=1;i<10;i++{ if i%5==0{ fmt.Println("我爱苍老师") }else if i%2==1{ fmt.Println("我爱波多老师") }else{ fmt.Println("我爱大桥未久") } time.Sleep(1*time.Second) } } func main(){ //for1() //for2() for3() }
range:
package main import "fmt" func main(){ s :="abc" for i :=range s{ fmt.Printf("下标%d,值=%c ",i,s[i]) } //直接都收到 for i,c :=range s{ fmt.Printf("下标%d,值=%c ",i,c) } for _,c :=range s{ fmt.Printf("值=%c ",c) } }
3.跳转语句
continue和break
package main import "fmt" func main(){ for i :=0;i<5;i++{ if i==2{ //break是直接打断,continue,跳过 //break //continue } fmt.Println(i) } }
goto:
package main import "fmt" func main(){ for i :=1;i<5;i++{ fmt.Println(i) //goto必须跳转到方法内 goto LABEL2 } fmt.Println("程序结束") LABEL2: fmt.Println("程序over") }
二.函数
1.自定义函数
函数声明格式:
方法名首字母大写是public,方法名首字母小写是private
func 函数名( [参数列表] ) [返回值列表] {
函数体
}
分类:
package main import "fmt" //无参数无返回值 func Test1(){ fmt.Println("公共的") } //有参数无返回值 func Test2(v1 int,v2 int){ fmt.Println(v1,v2) } //有不定参数无返回值 func Test3(args ...int){ //这边的前面是索引,后面的是值 for _,n :=range args{ fmt.Println(n) } } //无参数有返回值 func Test4()(a int,str string){ a=666 str="喜欢骑苍老师" return } func Test5()(int,string){ return 250,"喜欢被苍老师骑" } //有参数有返回值(求两个数的最大值和最小值) func Test6(num1 int,num2 int)(min int,max int){ if num1>num2{ min=num2 max=num1 }else{ min=num1 max=num2 } return } func main(){ Test1() Test2(1,2) Test3() Test3(1,2,3,4) fmt.Println(Test4()) fmt.Println(Test5()) fmt.Println(Test6(2,1)) }
例题:求1.。。100的和
package main import "fmt" // 循环实现1到100累加 func Test01() int { sum := 0 for i := 1; i <= 100; i++ { sum += i } return sum } //递归实现 //传100 func Test02(num int) int { if num == 1 { return 1 } return num + Test02(num-1) } func main() { fmt.Println(Test01()) fmt.Println(Test02(100)) }
2.defer关键字,延迟操作
defer⽤于延迟一个函数或者方法的执行
defer语句经常被用于处理成对的操作,如打开、关闭、连接、断开连接、加锁、释放锁
通过defer机制,不论函数逻辑多复杂,都能保证在任何执行路径下,资源被释放
释放资源的defer应该直接跟在请求资源的语句后,以免忘记释放资源
package main import "fmt" func test(x int) { fmt.Println(100 / x) } func main() { //defer是延迟操作 defer fmt.Println("aaaa") defer fmt.Println("bbbb") //报错并不影响程序运行 defer test(0) defer fmt.Println("cccc") }
三.复合类型
1.指针
go语言中指针是很容易学习的,比C中容易的多,它可以更简单地执行一些任务 与变量类似,使用前需要声明 声明指针的格式: var 指针变量名 *指针类型
简单使用:
package main import "fmt" func main(){ //声明变量 var a int=10 //声明指针 var p *int //指针变量储存 p=&a fmt.Printf("a变量的地址是%x ",&a) //指针变量的存储地址 fmt.Printf("p变量的指针地址%x ",p) //使用指针访问值 fmt.Printf("*p变量的值是:%d ",*p) }
使用指针改变所指向的内存的值
package main import "fmt" func main(){ //定义变量 var num int=10 fmt.Println(&num) //定义指针 var prt *int //g给指针赋值(指针指向哪个内存地址) prt=&num *prt=20 fmt.Println(num) //20 }
值传递和引用传递
go空指针,go空是用nil
答案 3,4
再看几个例子
package main import "fmt" //变量交换 //go方法是值传递 func swap(a,b int){ a,b =b,a } func main(){ a,b :=3,4 swap(a,b) fmt.Println(a,b) }
答案是3,4
package main import "fmt" //go方法参数是值传递 func swap(a,b *int){ *a,*b =*b,*a } func main() { a,b :=3,4 //指针是存地址的 swap(&a,&b) fmt.Println(a,b) }
答案是:4,3
另一种方法
package main import "fmt" //go方法参数是值传递 func swap(a,b int)(int,int){ return b,a } func main() { a,b :=3,4 //指针是存地址的 a,b=swap(a,b) fmt.Println(a,b) }
2.new和make
new()用来分配内存,但与其他语言中的同名函数不同,它不会初始化内存,只会将内存置零
make(T)会返回一个指针,该指针指向新分配的,类型为T的零值,适用于创建结构体
make()的目的不同于new(),它只能创建slice、map、channel,并返回类型为T(非指针)的已初始化(非零值)的值
看一个例子
package main import ( "fmt" ) func main(){ //未初始化 p :=new([] int) fmt.Println(p) //已经初始化 v:=make([] int,10,50) fmt.Println(v) //*p[0]=10 会报错,下标越界,未初始化为分配 v[0]=10 fmt.Print(v) }
3.数组
声明数组:
var 数组名[数组长度] 数组类型
声明和初始化数组
数组遍历
数组是值类型还是引用类型?
看一个例子
package main import "fmt" func main(){ //1.定义数组 //数组必须制定长度和类型 var arr1[5] int //:=创建,必须赋值 arr2:=[3] int{1,2,3} //3省累大小 arr3 :=[...]int{2,3,4,5,} fmt.Println(arr1,arr2,arr3) var grid[ 4][5]int fmt.Println(grid) //数组遍历 //1.直接遍历 for i:=0;i<len(arr3);i++{ fmt.Println(arr3[i]) } //2.range for i,v:=range arr3{ fmt.Println(i,v) } }
数组是值传递还是引用传递
package main import "fmt" func main(){ //1.定义数组 //数组必须制定长度和类型 var arr1[5] int //:=创建,必须赋值 arr2:=[3] int{1,2,3} //3省累大小 arr3 :=[...]int{2,3,4,5,} fmt.Println(arr1,arr2,arr3) var grid[ 4][5]int fmt.Println(grid) //数组遍历 //1.直接遍历 for i:=0;i<len(arr3);i++{ fmt.Println(arr3[i]) } //2.range for i,v:=range arr3{ fmt.Println(i,v) } }
数组和列表的区别,有类型,有大小,不可变
使用指针
package main import "fmt" //方法传入数组,修改元素 func printArr(arr *[5] int){ arr[0]=100 for i,v:=range arr{ fmt.Println(i,v) } } func main(){ //定义数组 var arr1 [5]int arr2 := [3]int{1, 2, 3} arr3 := [...]int{2, 4, 6, 8, 10} fmt.Println(arr1, arr2, arr3) printArr(&arr1) //不同长度,不能传参 //printArr(arr2) printArr(&arr3) fmt.Println() fmt.Println(arr1, arr3) }
说明是值传递
4.slice
数组的长度在定义之后无法再次修改,go语言提供了数组切片(slice)来弥补数组的不足
创建切片的各种方式
切片的操作
内建函数append()
内建函数copy()
切片的创建
package main import "fmt" func main(){ //声明切片和数组不一样的是不用指定大小 var s1 []int fmt.Println(s1) //:声明,必须{},:声明的必须赋值 s2:=[] int{} fmt.Println(s2) //make //诺写一个0.则代表大小和容量都是0 //var s3 [] int=make([] int,0) //d声明的时候大小为10,存11个也没问题 var s3 [] int=make([] int,10,10) fmt.Println(s3) s4 := []int{1, 2, 3} fmt.Println(s4) }
切片的操作(取值)
package main import "fmt" func main(){ //其切片取值 arr :=[...]int{1,2,3,4,5,6,7} fmt.Println("arr[2:6]=",arr[2:6]) fmt.Println("arr[:6]=",arr[:6]) fmt.Println("arr[2:]=",arr[2:]) fmt.Println("arr[:]=",arr[:]) }
内建函数append():向切片尾部添加数据
package main import "fmt" func main(){ var s1 [] int s1=append(s1,1) fmt.Println(s1) s1=append(s1,2,3) fmt.Println(s1) s1=append(s1,4,5,6) fmt.Println(s1) //创建指定大小的切片 s2:=make([] int,5) s2=append(s2,6) fmt.Println(s2) //创建并初始化切片 s3:=[]int{1,2,3} s3=append(s3,4) fmt.Println(s3) }
//从这个例子也能看出数组和切片的区别
go语言切片实际上是view操作
package main import "fmt" func main() { //1.go语言切片是对原数组的映射,并没有创建一个真正的切片 // 定义数组 arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7} //取切片 s1 := arr[2:] //修改值 s1[0] = 100 fmt.Println(s1) fmt.Println(arr) fmt.Println() // go语言切片没有取到的位置,可以向后延申,不可向前延申 s3 := arr[2:6] fmt.Println(s3) s4 := s3[3:5] fmt.Println(s4) //容量和大小 fmt.Printf("s3=%v,len(s3)=%d,cap(s3)=%d ", s3, len(s3), cap(s3)) }
append操作切片
package main import "fmt" func main() { //1.go语言切片是对原数组的映射,并没有创建一个真正的切片 // 定义数组 arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7} //取切片 s1 := arr[2:6] fmt.Println(s1) s2 := s1[3:5] fmt.Println(s2) s3 := append(s2,10) fmt.Println(s3) fmt.Println(arr) s4 := append(s3,11) fmt.Println(s4) fmt.Println(arr) s5 := append(s4,12) fmt.Println(s5) fmt.Println(arr) }
5.map
Map 是go内置的数据结构,是一种无序的键值对的集合,可以通过key快速找到value的值
定义Map:
var 变量名 map[key的数据类型] value的数据类型
创建map
初始化map
键值操作
遍历
删除
练习,创建5个方法,创建map,遍历map,删除键值对,修改map,map查询
6.结构体
go语言没有class,只是个结构体struct
结构体定义:
type 结构体名 struct{}
结构体初始化
7.结构体参数
结构体可以作为函数参数传递
四.面向对象
1.简介
go语言对于面向对象的设计非常简洁而优雅
没有封装、继承、多态这些概念,但同样通过别的方式实现这些特性
2.匿名字段
go支持只提供类型而不写字段名的方式,也就是匿名字段,也称为嵌入字段
同名字段的情况
所有的内置类型和自定义类型都是可以作为匿名字段去使用
指针类型匿名字段
3.方法
在面向对象编程中,一个对象其实也就是一个简单的值或者一个变量,在这个对象中会包含一些函数
这种带有接收者的函数,我们称为方法,本质上,一个方法则是一个和特殊类型关联的函数
方法的语法如下
func (接收参数名 接收类型) 方法名(参数列表)(返回值)
可以给任意自定义类型(包括内置类型,但不包括指针类型)添加相应的方法
接收类型可以是指针或非指针类型
为类型添加方法
值语义和引用语义
方法的继承
方法的重写
方法值和方法表达式
练习:创建属性的getter和setter方法并进行调用
4. 包和封装
方法首字母大写:public
方法首字母小写:private
为结构体定义的方法必须放在同一个包内,可以是不同的文件
5.接口
go语言中,接口(interface)是一个自定义类型,描述了一系列方法的集合 接口不能被实例化 接口定义语法如下 type 接口名 interface{} PS:接口命名习惯以er结尾 接口定义与实现 接口继承 空接口 类型查询 comma-ok断言 switch测试
6.面向对象练习
定义接口IPerson,定义吃喝睡三个抽象方法
定义结构体Person,实现上述方法
定义一个Person的实现类Worker即劳动者,拥有劳动方法Work()(output string)其中output是其工作产出,和休息方法Rest()
继承IWorker实现三个不同职业的子类:程序员Coder、老师Teacher、农民Farmer
创建一个IWorker的数组,将3个实例添加进去
main中测试工作日和周末,输出如下打印
五.异常处理
1.抛异常和处理异常
系统抛
自己抛