Go编程基础

2018-09-07  本文已影响0人  Jarily
  1. Go的优点
    • 高效垃圾回收机制
    • 类型安全和内存安全(没有隐式转换,只能显示转换)
    • 快速编译(未使用包检测)
    • 轻松实现高并发
    • 支持utf-8(源码文件格式为utf-8,type 哈哈 int)
    • 多核计算机(允许调用cpu核心数)
  1. GOPATH 工作目录

    bin pkg src
    可执行文件 包文件 .a 源代码
  2. GOROOT Go语言的安装目录

  3. 基本命令

    • go get 获取远程包(需提前安装git)
    • go run 运行
    • go build 测试编译(package main 的文件)
    • go fmt 格式化代码
    • go install 编译包文件和整个程序
    • go test 运行测试文件(**_test.go是测试文件,命名自己文件的时候需要注意)
    • go doc 查看文档(本地官网 go -http=:8080 & 后台执行)
  4. Go可见性规则

    • 首字母大小写决 常量,变量,类型,接口,结构 是否可以被外部调用
    • 函数名首字母小写=private
    • 函数名首字母大写=public
  5. Go类型和0值

    • 字符型 byte
    • bool 必须true、false。数字不行
    • 引用类型:slice,map,chan
    • func,可以赋值给变量
    • Go中指针没有->操作,只有.操作和&取地址,空指针为nil,不是null/NULL
  6. Go类型转换

    • 没有隐式转换,只能显示转换
    • 转换只能发生在两种相互兼容的类型之间(int<->float)
  7. 常量和常量枚举

    • iota是常量计数器,从0起,组中每定义一个常量自动递增1
    • 通过初始化规则和iota可以达到枚举效果
    • 每遇到一个const关键字,iota就重置为0
    const(
    a='A'
    b
    c=iota
    d
    )
    output a,b,c,d: 65 65 2 3
    
  8. Go控制语句

    • 加加/减减只能是语句,不能是表达式(a--正确,b=a--错误)
    • if/switch 前面可以跟一个初始化表达式,分号隔开
    • switch 不用break,匹配自动停,如果匹配还想继续,要fallthrough
    • goto; break; continue 可以配合标签名使用,跳转到标签处
  9. Go数组

    • 数组长度也算是类型
    • 数组用new初始化,返回指针 p := new([10]int)//p是指向数组的指针
    • 数组是值类型,传递的时候是拷贝的而不是传地址的
    • 数组之间可以==或者!=(不同类型的数组不可以做任何直接比较)
    a := [...]int{1, 2, 3}
    a :=[2]int
    中括号里面必须有东西才是数组,否则是切片
    切片中括号里面一定没有东西
    
  10. Go切片

    • 本身不是数组,指向底层数组,可以关联底层数组的局部或全部,用make初始化,new初始化不能用
    s1 := []int{tt: 1}
    s1 := make([]int, tt)
    如果tt是const 都正确,不是则第一个错误 
    
    • copy函数 copy(s1,s2)
    • append函数
    s1 := make([]int,3,7)
    则有
        len(s1) = 3
        cap(s1) = 7
    append(s1,1,2,3,6,7,8,9,0,0,1)
    此时s1长度越界,内存地址改变
    
    
  11. Go语言map

    • 三种定义方式
    var m map[int]string
    m = map[int]string{}
    
    m := make(map[int]string,cap) //cap为指定容量,超出自动扩容
    
    m := map[int]string{1:"a",2:"b",3:"c"}
    
    • delete 删除键值对

    • 使用for range 对map和slice进行迭代操作

    • 多层map使用

    var m map[int]map[int]string
    m = make(map[int]map[int]string)
    //m[1] = make(map[int]string)
    //m[1][1]="OK"
    a, ok := m[1][1]
    if !ok {
        m[1] = make(map[int]string)
    }
    m[1][1] = "GOOD"   //right
    
  12. Go语言函数

    • 函数不支持嵌套/重载和默认参数
    • 无需声明原型
    • 不定长度变参
    func A(b string, a ...int){ //a必须是最后一个参数, a为一个切片
        
    }
    
    • 多返回值/命名返回值参数
    • 匿名函数
    func main(){
        a := func(){ //匿名函数
            fmt.Printfln("func A")  
        }
    }
    
    
    • 闭包
    func main(){
        f := closure(10)
        fmt.Printfln(f(1))  // 11
        fmt.Printfln(f(2))  // 12
    }
    func closure(x int) func(int) int {
        return func(y int ) int {
            return x + y
        }
    }
    
    • 函数也可以作为一种类型使用
    func main(){
        a := A
        a()
    }
    func A(){
        fmt.Printfln("func A")
    }
    
  13. defer

    • 执行方式类似于其他语言的析构函数,在函数体执行结束后按照调用顺序的相反顺序逐个执行(栈)
    • 即使函数发生严重错误也会执行
    • 支持匿名函数的调用
    • 常用于资源清理/文件关闭/解锁以及记录时间等操作
    • 通过与匿名函数配合可在return之后修改函数计算结果
    • 如果函数体内某个变量作为defer时匿名函数的参数,则在定义defer时即已获得了拷贝,否则则是引用某个变量的地址
    func main(){
        for i := 0; i < 3; i++ {
            defer func() {
               fmt.Println(i) 
            }()
        } 
    }
    
    输出:
    3
    3
    3
    
    • Go没有异常机制,使用panic/recover模式来处理错误
    • panic可以在任何地方引发,但recover只有在defer调用的函数中有效
    func main() {
        A()
        B()
        C()
    }
    
    func A() {
        fmt.Println("func A")
    }
    
    func B() {
        defer func() {  //recover只有在defer调用的函数中有效
            if err := recover(); err != nil { //panic阻断了运行,执行下面的回府
                fmt.Println("Recover in B")
            }
        }()
        panic("Panic in B") //到这儿挂了
    }
    
    func C() {
        fmt.Println("func C")
    }
    
    输出:
    func A
    Recover in B
    func C
    
  14. Go结构struct

    • 嵌套结构,类似于继承
    type human struct {
        sex int
    }
    
    type teacher struct {
        human
        age  int
        city string
    }
    
    func main() {
        a := teacher{}
        a.sex = 5
        a.city = "enshi"
        //a := teacher{human: human{sex: 1}}
        fmt.Println(a)
    }
    
    
    • 匿名结构
    a := &struct {
      Name string
      Age int
    }{
      Name: "Joe",
      Age : 19,
    }
    fmt.Println(a)
    
    • method
    func(a *A)print(){}
    调用的时候 a.print
    A类型的a是接收者
    
  15. Go接口interface

    • 接口是一个或多个方法签名的集合
    • 只有声明,没有实现,没有数据字段
    • 接口可以匿名嵌入到其他接口,或嵌入到结构中
    • 实现接口:structural typing,只要实现某类型拥有该接口所有方法的签名,就算是实现接口
    • 通过接口实现类似继承的功能,可以实现类似多态
    • go中所有类型都实现了空接口,空接口可以作为任何类型数据的容器
    • 接口转换,大接口转小接口可以,嵌套进去的小接口转不了大接口
    • 对象赋值给接口时发生拷贝, 所以不能通过修改对象改变接口内容
    • 只有当接口存储的类型和对象都是nil的时候, 接口才是nil,如果接口里存的是指向nil的指针,也不行
    • 接口调用不会做receiver的自动转换
    • 类型断言 ok pattern/ type switch 类型判断,接口转换
  16. Go反射reflection

    • 反射可大大提高程序的灵活性,是的interface{}有更大的发挥余地
    • 反射使用TypeOf和ValueOf函数从接口中获取目标对象信息
    • 反射会将匿名字段作为独立字段(匿名字段本质)
    • 想要利用反射修改对象状态,前提是interface.data是settable,即pointer-interface
    • 通过反射可以“动态”调用方法
  17. Go并发

    • 每个实例4-5k,轻便

    • 并发不是并行:并发是由切换时间来实现“同时”运行,并行是多核多线程

    • goroutine 通过通信来共享内存,而不是共享内存来通信

    func main() {
        wg := sync.WaitGroup{}
        for i := 0; i < 10; i++ {
            wg.Add(1)
            go Go(&wg, i)
        }
        wg.Wait()
    }
    
    func Go(wg *sync.WaitGroup, ind int) {
        a := 1
        for i := 0; i < 10000; i++ {
            a += i
        }
        fmt.Println(ind, a)
        wg.Add(-1) //wg.Done()
    }
    
    
    • Channel
      • Channel是goroutine沟通的桥梁,大都是阻塞同步的
        • 有缓存的是异步的,无缓存的是同步阻塞
      • 通过make创建,close关闭
      • Channel是引用类型
      • 可以使用for range 来迭代不断操作channel
      func main() {
          c := make(chan bool, 10)
          for i := 0; i < 10; i++ {
              go Go(c, i)
          }
          for i := 0; i < 10; i++ {
              <-c
          }
      
      }
      
      func Go(c chan bool, ind int) {
          a := 1
          for i := 0; i < 10000; i++ {
              a += i
          }
          fmt.Println(ind, a)
          c <- true
      }
      
      
      • 可以设置单向或双向通道
      • 可以设置缓存大小,在未被填满前不会发生阻塞
    • Select
      • 可处理一个或多个channel的发送与接收(类似于switch)
      • 同时有多个可用的channel时按照随机顺序处理
      • 可用空的select来阻塞main函数
      func main(){
          select{}    //死循环
      }
      
      • 可设置超时
      func main(){
          c := make(chan int)
          select{
              case v := <- c:
                  fmt.Println(v)
              case <- time.After(3*time.Second): //返回的是一个chan
                  fmt.Println("Timeout!")
          }
      }
      
上一篇下一篇

猜你喜欢

热点阅读