美文网首页
Go编程基础

Go编程基础

作者: Jarily | 来源:发表于2018-09-07 15:04 被阅读0次
    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!")
            }
        }
        

    相关文章

      网友评论

          本文标题:Go编程基础

          本文链接:https://www.haomeiwen.com/subject/qlecgftx.html