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 () 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 () int ){    res=55      return  } func  Myfunc03 () int ,int ,int ){    return  1 ,2 ,3  } func  Myfunc03 () 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) 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 ) 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) 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)     ... } func  (h *Human) 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 ) 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" )