Go语言的学习与应用(偏后端) golang的中文文档网址 http://studygolang.com/pkgdoc
go语言的入门 01 认识它 1 2 go build ***.go go run ***.go
02 数据类型 准备工作 必须引入main包 import导入“头文件” 1 2 package mainimport "fmt"
赋值 注意:变量声明了,就一定要用不然会报错 =是赋值,:=是声明自动推导变量 1 2 3 4 5 6 7 8 9 10 11 12 var a int var a,b int var c=10 d:=30 d=20 var { a int b float64 }
Println和Printf Println是换行
Printf可以格式化
1 2 3 a,b:= 20 ,30 fmt.Println("a=" ,a,"b=" ,b) fmt.Printf("a=%d,b=%d" ,a,b)
多重赋值 匿名变量 丢弃数据不处理,一般配合返回值使用
1 2 3 4 5 6 func test () (a,b,c int ){ return 1 ,2 ,3 } var a,b,c int a,b,c=test() _,b,_=test()
常量 1 2 3 4 5 6 7 const a int =10 const b=10 ;const { c =10 d =3.14 }
浮点 1 2 3 var a float64 var b float32
字符类型 fmt格式化输出 其他都和c语言差不多,**%v是万能格式**,写了自动推导输出 %T,输出的是变量类型 输入 1 2 3 4 var a int fmt.Scan(&a) fmt.Scanf("%d" ,&a)
类型别名 1 2 3 4 5 6 7 8 9 type bigint int64 bigint a type { long int64 char byte } var b longvar c char
range 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 str:="abc" for i:=0 ;i<len (str);i++{ fmt.Printf("str[%d]=%c\n" ,i,str[i]) } for i,data:=range str{ fmt.Printf("str[%d]=%c\n" ,i,data) } for i:=range str{ fmt.Printf("str[%d]=%c\n" ,i,str[i]) } for i,_:=range str{ fmt.Printf("str[%d]=%c\n" ,i,str[i]) }
03函数 格式 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 32 33 34 35 36 37 func Myfunc () { fmt.Println("hhhh" ); } func Myfunc01 (a,b int ) { a=111 fmt.Println(a) } func Myfunc02 (args ...int ) { for i:=0 ;i<len (args);i++{ fmt.Printf("args[%d]=%d\n" ,i,args[i]) } } func main () { Myfunc02(1 ,2 ,3 ) Myfunc02(1 ,2 ) } func Myfunc03 () (res int ){ res=55 return } func Myfunc03 () (int ,int ,int ){ return 1 ,2 ,3 } func Myfunc03 () (a int ,b int ,c int ){ a,b,c=1 ,2 ,3 return }
函数类型(多态性) 函数也是可以当做类型赋值,甚至还有多态性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 func Add (a,b int ) int { return a+b } func Minus (a,b int ) int { return a-b } type FuncType func (int ,int ) int func main () { var res int var functest FuncType functest=Add res=functest(1 ,2 ) funtest=Minus res=functest(10 ,7 ) }
回调函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 type FuncType func (int ,int ) int func Add (a,b int ) int { return a+b } func Minus (a,b int ) int { return a-b } func Calc (a,b int ,fTest FuncType) (res int ){ fmt.Println("回调函数" ) res=fTest(a,b) return } func main () { var res int res=Calc(1 ,2 ,Add) res=Calc(4 ,3 ,Minus) }
匿名函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 f1:=func () { fmt.Println("哈哈哈哈哈" ) } f1(); type FuncType func () var f2 FuncTypef2=f1 f2() x,y:=func (a,b int ) (max,min int ){ if a<b{ max=b min=a }else { max=a min=b } return }(10 ,20 )
闭包 我觉得这一点跟C有区别一点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 func Test () func () int { var x int =0 return func () int { x++ return x*x } } func main () { f:=Test() fmt.Println(f()) fmt.Println(f()) fmt.Println(f()) fmt.Println(f()) }
defer 延迟调用,只用在大括号里
1 2 3 4 5 defer fmt.Println("hhhhh" )fmt.Println("jjjjj" )
多个defer的调用顺序:和栈一样:先写的后调用,后写的先调用
注意:
如果defer的语句有错误,依旧能继续调用下方的代码 有defer关键词的正常代码会按照栈的顺序执行 有defer关键词的错误代码会在正常defer语句执行 defer和匿名函数 如果有传参的话,是按顺序该传就传,只不过被传参的函数是defer延时调用的
获取命令行参数(os.Args) os.Args是用户输入的以空格相隔的字符串切片(string[]) 使用方式:cmd,终端第一种:go build生成可运行.exe,再运行.exe输入以空格为间隔的多个字符串,注意输入的第一个字符在切片中的下标为1,(因为下标为0的是该.exe的名字) 第二种:go run直接接空格输入字符串组,同样输入的第一个字符串下标为1 工程管理 建一个工程,将源码放入src文件管理 同级目录引入的包应该相同package main,且调用同级不同文件的函数可以直接调用 不同级目录调用函数引入包名import 调用:包名.函数名 函数一定是大写字母开头不然调用不了 04复杂类型 数组 注意:数组做函数参数是值传递(值拷贝):即函数内部改变数组元素不会影响原来的数组
所以如果想要用函数改变数组元素要用数组指针,地址传递
1 2 3 4 5 6 7 8 9 10 func f (a [7]int ) { a[2 ]=999 } func f1 (p *[7]int ) { (*p)[2 ]=999 } a:=[7 ]int {1 ,2 } f(a) f1(&a)
1 2 3 var a [50 ]int b:=[5 ]int {1 ,2 ,3 }
切片 本质上不是数组
长度可以不固定
1 2 3 4 5 6 7 a:=[]int {1 ,2 ,3 ,4 ,5 } s:=make ([]int ,5 ,10 ) s:=make ([]int ,5 )
切片与底层数组 切片截取的片段元素改动,那么被截取的原数组(切片)也会改变 另外在上述切片上再定义一个新切片,也是建立在原数组的基础上的:即取值范围可以超过上述切片,不要超过原数组就行 1 2 3 4 5 6 a:=[]int {1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 } slice:=a[0 :4 ] slice[0 ]=100 newslice:=slice[2 :7 ] newslice[2 ]=1000
1 2 3 4 5 6 7 8 a:=[]int {1 ,2 ,3 ,4 ,5 } slice:=a[0 :4 :5 ]
append()的扩容速度:在超过原来的通量后以2倍的速度扩容
切片做函数参数 和之前讲过的数组不一样,(感觉更接近于C中的数组,不用特意用地址传递,也能在函数内部影响外部)
1 2 3 4 5 6 func Test (s []int ) { s[0 ]=222 } s:=[]int {1 ,2 ,3 ,4 } Test(s)
随机数 1 2 3 rand.Seed(time.Now().UnixNano()) rand.Intn(100 )
map 只有len没有cap,也可以说len即cap,也是随着创建会自动扩容的
键值是唯一的
map是无序的,与创建顺序无关
1 2 3 4 5 6 7 8 9 10 11 12 13 var m1 map [int ]string m2:=make (map [int ]string ) m3:=make (map [int ]string ,10 ) value,ok:=m2[1 ] if ok==true { fmt.Println("m2[1]=" ,value) }else { fmt.Println("key不存在" ) }
删除 map做函数参数 也是和切片一样是引用传递:即内部影响外部
05结构体 创建结构体 1 2 3 4 5 6 7 8 9 10 11 12 13 14 type Student struct { num int name string sex byte age int addr string } func main () { var s Student=Student{1 ,"czy" ,'f' ,20 ,"翻斗花园" } s1:= Student{name:"orange" ,addr:"化成花园" } }
new和结构体指针 跟C差不多,不过没有->符号(怪难受的)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 type Student struct { num int name string sex byte age int addr string } var p1 *Studentp1=new (Student) p1.num=1 ; p1.name="mingming" (*p1).name="czy" var s Studentvar p2 *Studentp2:=&s p2.name="guangguang"
如果想在不同的包里使用结构,并且创建其属性,那么在创建结构体的时候一定要首字母大写
06方法 带接收者的函数叫方法
但接收者类型本身不能是pointer
1 2 3 4 5 6 7 8 9 10 func (p *Person) Setinfo(n string ,s byte ,a int ){ p.name=n; p.sex=s; p.a=age; } func main () { var p Person (&p).Setinfo("czy" ,'f' ,20 ) }
07接口 知道怎么写就好啦,只有方法声明,没有实现也没有数据字段 习惯使用”er”结尾来命名接口 有点涉及到Java的向上转型,多态性 继承接口的结构体都是直接把接口写在属性列表里 上述结构体只能进行向上转型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 type Humaner interface { SayHi() } type Human struct { Humaner Sing(lyrics string ) } func (h *Human) SayHi(){ ... } func (h *Human) Sing(lyrics string ){ ... }
空接口 弹幕:“类似于Java中的Object类”,我觉得有道理
异常处理(我终于搞懂了) error接口的应用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import "errors" func MyDiv (a, b int ) (res int ,err error ){ err=nil ; if b==0 { err=errors.New("分母不能为0" ) }else { res=a/b; } return } func main () { res,err:=MyDiv(10 ,2 ) if (err!=nil ){ fmt.Println("err=" ,err) }else { fmt.Println("res=" ,res) } }
panic函数(崩程序 显式调用panic函数 1 panic ("this is a panic test" )
数组越界导致panic 反正就是数组如果写了越界了,panic函数自己就跳出来报错中断程序了
recover(解决程序崩 解决panic中断程序,必须和defer一起使用
1 2 3 4 5 6 7 8 9 10 11 12 func test (x int ) { defer func () { recover () if err:=recover ();err!=nil { fmt.Println(err) } }() var a [10 ]int a[x]=10 ; }
08文本文件的处理 1 2 import "strings" import "strconv"
字符串操作 Contains是否包含字符串
1 func Contains (s,substr string ) bool
Join连接字符串
Index查找位置
1 func Index (s,sep string ) int
字符串转换 Append系列是各种类型追加到字符串(有需要查看文档吧)
Format系列都是把别的类型转为字符串(有需要查看文档吧)
·字符串转其他类型:Parase系列
1 2 3 4 5 6 flag,err:=strconv.ParaseBool("true" ) if err!=nil { fmt.Println("err=" ,err) }else { fmt.Println("flag=" ,flag) }
字符串转整型
1 a,_:=strconv.Atoi("567" )