优势:

  • 极简单的部署方式:可直接编译成机器码,不依赖其他库,直接运行即可部署
  • 静态类型语言:
    • 编译的时候检查出来隐藏的大多数问题
  • 语言层面的并发:
    • 天生支持
    • 充分利用多核
  • 标准库:
    • runtime系统调度机制
    • 高效的GC垃圾回收
    • 丰富的标准库
  • 简单易学
    • 25个关键字
    • C语言简洁基因
    • 跨平台
    • 面向对象

缺点:

  • 无泛化类型
  • 包管理大部分都在github上
  • 所有Exception都用error来处理
  • 对C的降级处理不是无缝的,不像C->asm那么完美(序列化问题)

Hello world

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main(){
  6. var a int = 1
  7. fmt.Println("hello go!")
  8. }

变量,常量

变量 var

有var就是=
没有就是:=

  1. 方法1:声明一个变量,默认值是0
  2. var a int
  3. //默认a=0
  4. 方法2:声明一个变量并初始化
  5. var b int = 10
  6. 方法3:初始化时省略数据类型,自动匹配
  7. var c = 10
  8. //自动推导
  9. 方法4:直接自动匹配//不支持全局变量
  10. d:= 10

多个变量声明

  1. 单行写法
  2. var aa,bb int =100,200
  3. var cc,dd = 100, "miao"
  4. 多行写法
  5. var(
  6. vv int = 100
  7. gg bool = true
  8. )

常量,枚举,const与iota

  1. const 关键字可以用于定义常量
  2. const a int = 10
  3. const还可以定义枚举类型,iota用在const中作为一个每行+1的量 第一行iota=0 公式不变
  4. const (
  5. SHANGHAI = 1
  6. SHENZHEN = 2
  7. BEIJING = 3
  8. )
  9. 与以下是一样的
  10. const (
  11. SHANGHAI = iota
  12. SHENZHEN
  13. BEIJING
  14. )
  15. //=================================
  16. const (
  17. SHANGHAI = 10*iota
  18. SHENZHEN
  19. BEIJING
  20. )
  21. 相当于
  22. const (
  23. SHANGHAI = 0
  24. SHENZHEN = 10
  25. BEIJING = 20
  26. )
  27. //================================
  28. const (
  29. a,b = iota + 1, iota +2 //1,2
  30. c,d //2,3
  31. e,f = iota*2, iota*3 //6,9
  32. c,d //8,12
  33. )

函数,多返回值

多返回值

  1. func foo1(a string, b int) {
  2. blabla
  3. }
  4. func foo2(a string, b int) int {
  5. blabla
  6. c:=10
  7. return c
  8. }
  9. func foo3(a string, b int) (int,int) {
  10. blabla
  11. c,d:=10,20
  12. return c,d
  13. }
  14. func foo4(a string ,b int)(r1 int,r2 int){
  15. r1:=10
  16. r2:=20 //不赋值则默认0
  17. //作用域是函数体整个空间内
  18. return
  19. }

通常把对外开放的函数大写开头,私有函数小写开头

init函数与import导包

image.png
先层层import,init()执行后再返回
引入路径填相对于gopath的路径
可以给包起别名

  1. import(
  2. _ "xxxx/xxxx" //匿名导入 可以不使用包内方法,但是init
  3. mylib "yyyy" //mylib.AAA() 可以使用包的方法
  4. "qqqqq/cccc"
  5. . "qqqqqqqqqq" //导入包中的全部方法 可以直接调用不需要加包名
  6. )

指针,引用

p 根据地址找内存
&a 取地址
p := &a p是
int类型的
可以多多多级指针

defer

defer后面的表达式在结束之前执行,类似于析构函数,是一种压栈的形式
return先执行,defer后执行

  1. func A(){
  2. }
  3. func B(){
  4. }
  5. func C(){
  6. }
  7. func E(){
  8. }
  9. func main(){
  10. defer A()
  11. defer B()
  12. defer C()
  13. defer fmt.Println("D")
  14. return E()
  15. }
  16. E
  17. D
  18. C
  19. B
  20. A

数组,切片slice

  1. var myArray1 [10]int //普通数组
  2. var myArray2 [4]int{1,2,3,4} //普通数组
  3. for i:=0 ;i< len(myArray1);i++ {
  4. fmt.Println(myArray1[i])
  5. }
  6. for index,value := range myArray2{
  7. fmt.Println("index=",index,"value=",value)
  8. }
  9. 数组在函数中传递时候传递的是一个拷贝的值,且根据不同的长度有不同的类型
  10. myArray1 的类型是[10]int, myArray2的类型是[4]int,在函数传递的时候会类型不匹配
  11. func A(arr [4]int) {
  12. arr[0]=10 //无法改变实际上的arr[0]
  13. }

切片数组

  1. myArray:=[]int{1,2,3,4}
  2. func A(arr []int) {//引用传递
  3. arr[0]=10 //可以改变实际上的arr[0],传的是一个指针
  4. }

slice四种声明方式

  1. var a =make([]int,15)
  2. slice1 := []int{1,2,3}
  3. var slice2 []int
  4. slice2 = make([]int,3)
  5. var slice3 []int =make([]int,3)
  6. slice4 := make([]int,3)

判断slice是否为空

  1. if slice1 == nil {
  2. blabla 空切片
  3. }else{
  4. blabla 分配过的切片
  5. }

slice切片与追加

  1. var a =make([]int,35) //长度3容量5
  2. a=append(a,1) //长度4容量5
  3. a=append(a,2) //长度5容量5
  4. a=append(a,3) //长度6容量10 超出容量的时候容量会x2
  5. var b =make([]int,3) //长度3容量3 如果扩容就变成6

扩容机制:超出容量的时候容量会x2

截取

  1. s := []int{1,2,3}
  2. s1 := s[0:1] //前闭后开,和python一样 默认上限len(s),默认下限0 [1:], [:2]都是可以的

这里指向的底层地址一致,改s1[0]也会改变s[0]
可以用copy得到深拷贝

  1. s2:= mask([]int,3)
  2. copy(s2,s) //s中的值拷贝至s2

image.png

map

  1. 三种声明方式
  2. //方法1
  3. 声明 MyMap1是一种map类型,keystringvalueint
  4. var myMap1 map[string]int
  5. 目前myMap1==nil
  6. myMap1=make(map[string]int,10) 使用map前需要先用makemap分配数据空间 一样能够自动扩容
  7. myMap1["one"]=10
  8. myMap2["two"]=20
  9. 必须make否则会报错
  10. //方法2
  11. myMap2 := make(map[string]int)
  12. myMap2["one"]=10
  13. myMap2["two"]=20
  14. //方法3
  15. myMap3 := map[string]string{
  16. "one":10,
  17. "two":20,
  18. }
  19. //===========================
  20. 使用
  21. //===========================
  22. //添加 略
  23. //遍历
  24. for key,value := range myMap3{
  25. fmt.Println(key,value)
  26. }
  27. //删除
  28. delete(myMap3,"one")
  29. //修改和添加一样
  30. //传参的时候传的是指针
  31. func changeMap(mapa map[string]int){ //引用传递
  32. mapa["one"]=1
  33. }
  34. //完全拷贝需要再定义一个map把值复制过去

struct类与对象

  1. type myint int
  2. //声明一个int的别名叫myint
  3. //定义一个结构体
  4. type Book struct{
  5. title string
  6. auth string
  7. }
  8. func changeBook1(book Book){ //值传递
  9. book.auth = "444" //不会变
  10. }
  11. func changeBook2(book *Book){
  12. book.auth = "111" //会变
  13. }
  14. func main(){
  15. var book1 Book
  16. book1.title = "golang"
  17. book1.auth = "zhang3"
  18. fmt.Printf("%v\n",book1)//会逐个输出Book中的变量值
  19. //输出的会是 {golang zhang3}
  20. changeBook1(book)
  21. fmt.Printf("%v\n",book1)
  22. //输出的会是 {golang zhang3}
  23. changeBook2(&book1)
  24. fmt.Printf("%v\n",book1)
  25. //输出的会是 {golang 111}
  26. }

  1. //如果类名首字母大写表示其他包也能够定义这个对象
  2. type Hero struct{
  3. Name string //如果说类的属性首字母大写表示该属性共有,否则的话只能够类的内部访问
  4. Ad int
  5. level int //私有属性
  6. }
  7. func (this *Hero) Show(){ //方法首字母大写表示在其他包中能够调用 小写表示其他包不能调用
  8. fmt.Println("",........)
  9. }
  10. func (this Hero) SetName(a strnig){ //这里传递的是this的一个拷贝
  11. this.Name=a
  12. }
  13. func (this *Hero) SetName(a string){
  14. this.Name=a
  15. }
  1. 注意this* 否则只能访问一个副本
  2. 注意首字母大小写有区别,大写表示对外访问,小写只能在本包内访问

继承

  1. type Human struct{
  2. name string
  3. sex string
  4. }
  5. func (this *Human) Eat(){
  6. fmt.Println("Human.Eat()")
  7. }
  8. func (this *Human) Walk(){
  9. fmt.Println("Human.Walk()")
  10. }
  11. typedef Superman struct{
  12. Human //Superman类继承了Human类的方法
  13. level int
  14. }
  15. //重定义父类方法
  16. func (this* Superman) Eat(){
  17. fmt.Println("Superman.Eat()")
  18. }
  19. //子类新方法
  20. func (this* Superman) Fly(){
  21. fmt.Println("Superman.Eat()")
  22. }
  23. func main(){
  24. h:=Human{"zhang3","female"}
  25. h.Eat()
  26. h.Walk()
  27. s:=Superman{Human{"li4","male"},88}
  28. //或者
  29. var s Superman
  30. s.name = "li4"
  31. s.sex = "male"
  32. s.level = 88
  33. s.Walk() //human walk
  34. s.Eat() //superman eat
  35. s.Fly() //superman fly
  36. }

多态 interface

基本要素

  • 有一个父类
  • 有子类,实现了父类的全部接口方法
  • 父类类型的变量(指针) 指向(引用) 子类的具体数据变量 ```go type AnimalIF interface{ //是一个指针!!!!!!!!!!!!!!!! Sleep()
    GetColor() string //获取动物的颜色 GetType() string //获取动物的种类 }

//不需要把AnimalIF显式写下来,重写该接口的[所有]方法,就可以用一个AnimalIF指针指向Cat type Cat struct{ color string }

func (this* Cat) GetColor(){ return this.color }

func (this* Cat) GetType(){ return “Cat” }

func (this* Cat) Sleep(){ fmt.Println(“Cat sleeping”) }

type Dog struct{ color string }

func (this* Dog) GetColor(){ return this.color }

func (this* Dog) GetType(){ return “Dog” }

func (this* Dog) Sleep(){ fmt.Println(“Dog sleeping”) }

func showAnimal (animal AnimalIF){ animal.Sleep() //多态 fmt.Println(“color = “,animal.GetColor()) }

func main(){

  1. var animal AnimalIF //接口数据类型
  2. animal = &Cat{"Green"}
  3. animal.Sleep()
  4. animal = &Dog("Yellow")
  5. animal.Sleep()
  6. showAnimal(animal)
  1. <a name="gs0sb"></a>
  2. ## 空接口 interface{} 通用万能类型,类型断言
  3. int、string、float32、float64、struct 都实现了 interface
  4. ```go
  5. func myFunc(arf interface{}){
  6. fmt.Println("myFunc called")
  7. fmt.Println(arg)
  8. //interface{}实际类型区分办法:断言
  9. value,ok := arg.(string)
  10. if ok{
  11. 是string类型
  12. }else{
  13. 不是string类型
  14. fmt.Printf("value type is %T\n", value)
  15. }
  16. }
  17. type Book struct{
  18. auth string
  19. }
  20. func main(){
  21. bool:= Book{"Golang"}
  22. myFunc(book)
  23. myFunc(100)
  24. }

反射

变量的结构

image.png
反射 通过一个变量得到type、值

  1. var a string
  2. //pair<statictype:string, value:"aceld">
  3. a="aceld"
  4. //pair<type:string,value:"aceld">
  5. var allType interface{}
  6. allType = a
  7. str,_:=allType.(string)
  8. fmt.Println(str) //aceld

断言可以用于强制转换

image.png
pair是不会变的.

image.png
image.png

reflect包:ValueOf,TypeOf

动态获取未知数据类型和值

  1. package main
  2. import(
  3. "fmt"
  4. "reflect"
  5. )
  6. func reflectNum(arg interface{}){
  7. fmt.Println("type:", reflect.TypeOf(arg)," value:",reflect.ValueOf(arg))
  8. }
  9. type User struct{
  10. Id int
  11. Name string
  12. Age int
  13. }
  14. func (this* User) Call(){
  15. fmt.Println("User id called ..")
  16. fmt.Printf("%v\n", this)
  17. }
  18. func man(){
  19. var num float64 = 1.2345
  20. user:= User{1,"Aceld",18}
  21. }
  22. func DoFIleAndMethod(input interface{}){
  23. //获取type
  24. inputType:= reflect.TypeOf(input)
  25. fmt.Prinln("type is ",inputType.Name())
  26. //获取value
  27. inputValue:= reflect.ValueOf(input)
  28. fmt.Prinln("value is ",inputValue)
  29. //通过type获取里面的字段
  30. for i :=0; i< inputType.NumField(); i++{
  31. field := inputType.Field(i)
  32. value := inputValue.Field(i).Interface()
  33. fmt.Printf("%s:%v = %v\n",field.Name,field.Type,value)
  34. }
  35. //通过type获取里面的方法,调用
  36. for i := 0; i< inputType.NumMethod();i++{
  37. m:=inputType.Method(i)
  38. fmt.Printf("%s:%v\n",m.Name,m.Type)
  39. }
  40. }

image.png
详细接口看文档

结构体标签

  1. type resume struct{
  2. Name string `info:"name" doc:"我的名字"`
  3. Sex string `info:"sex"`
  4. }
  5. func findTag(str interface{}){
  6. t:=reflect.TYpeOf(str).Elem()
  7. for i:=0; i<t.NumField();i++{
  8. taginfo :=t.Field(i).Tag.Get("info")
  9. tagdoc := t.Field(i).Tag.Get("doc")
  10. }
  11. }
  12. func main(){
  13. var re resume
  14. findTag(&re)
  15. }

结构体标签在json中的使用

image.png

可以应用在json编解码,orm映射关系等