Golang入门

27 篇文章 0 订阅
20 篇文章 0 订阅

go 入门

  • 基础

    • 目录结构src pkg bin,gopath是工作目录环境变量,查看go env
    • main.main() 函数(这个函数位于主包)是每一个独立的可运行程序的入口点。
    • 除了 main 包之外,其它的包最后都会生成 *.a 文件(也就是包文件)并放置在 G O P A T H / p k g / GOPATH/pkg/ GOPATH/pkg/GOOS_$GOARCH 中
    • 用 var 方式来定义全局变量,:= 进行在函数内的简短声明,_ 特殊的变量名,任何赋予它的值都会被丢弃。
    • 字符串使用""或``,其不可变,但可以进行切片操作;内置error错误类型;
  • 分组声明

    import(
        "fmt"
        "os"
    )

    const(
        i = 100
        pi = 3.1415
        prefix = "Go_"
    )

    var(
        i int
        pi float32
        prefix string
    )
  • iota枚举关键字与常量

    • 默认开始值是 0,const 中每增加一行加 1
    • 每遇到一个 const 关键字,iota 就会重置
    • 常量声明省略值时,默认和之前一个值的字面相同
    • 在同一行值相同
  • go程序设计规则

    • 大写字母开头的变量,公有变量,可导出。小写则是私有变量。
  • array, slice, map

    • 声明 slice 时,方括号内没有任何字符。slice 的 index 只能是 int 类型

    • 数组之间的赋值是值的赋值,传入的其实是该数组的副本,而不是它的指针

          //array
          var arr [10]int     // 声明了一个int类型的数组
          b := [10]int{1, 2, 3} // 声明了一个长度为 10 的 int 数组,其中前三个元素初始化为 1、2、3,其它默认为 0
          c := [...]int{4, 5, 6} // 可以省略长度而采用 `...` 的方式,Go 会自动根据元素个数来计算长度
      
          //slice, 和声明 array 一样,只是少了长度
          var fslice []int
          // 声明并初始化
          slice := []byte {'a', 'b', 'c', 'd'}
          //  a 指向数组的第 3 个元素开始,并到第五个元素结束,左开右闭
          a = ar[2:5]
          // 第三个参数指定切片容量
          slice = array[2:4:7]
      
  • slice 引用类型 常用简便操作

    • slice 的默认开始位置是 0,ar[:n] 等价于 ar[0:n]
    • slice 的第二个序列默认是数组的长度,ar[n:] 等价于 ar[n:len(ar)]
    • 如果从一个数组里面直接获取 slice,可以这样 ar[:],即等价于 ar[0:len(ar)],包含了全部的元素
  • slice 常用内置函数

    • len 获取 slice 的长度
    • cap 获取 slice 的最大容量
    • append 向 slice 里面追加一个或者多个元素,然后返回一个和 slice 一样类型的 slice
    • copy 函数 copy 从源 slice 的 src 中复制元素到目标 dst,并且返回复制的元素的个数
  • map

        var numbers map[string]int
    
        numbers = make(map[string]int)
        numbers["one"] = 1  // 赋值
    
        rating := map[string]float32{"C":5, "Go":4.5, "Python":4.5, "C++":2 }
        // map 有两个返回值,第二个返回值,如果不存在 key,那么 ok 为 false,如果存在 ok 为 true
        csharpRating, ok := rating["C#"]
    
    • 通过delete删除map的元素
    • map 也是一种引用类型,如果两个 map 同时指向一个底层,那么一个改变,另一个也相应的改变
    • map 和其他基本型别不同,它不是 thread-safe,在多个 go-routine 存取时,必须使用 mutex lock 机制
  • make vs new

    • new 用于各种类型的内存分配。new 返回指针,即*T类型的值
    • make 用于内建类型(map、slice 和 channel)的内存分配。make 返回一个有初始值(非零)的T类型,而不是 *T
    • 零值并非是指空值,而是一种变量未填充前的默认值,通常为0
          // 常用零值列表
          int     0
          int8    0
          int32   0
          int64   0
          uint    0x0
          rune    0 // rune 的实际类型是 int32
          byte    0x0 // byte 的实际类型是 uint8
          float32 0 // 长度为 4 byte
          float64 0 // 长度为 8 byte
          bool    false
          string  "
      

流程控制

  • if 条件判断(许初始化变量)
    • 条件判断语句里面允许声明一个变量,该变量的作用域只能在该条件逻辑块内
  • goto 无条件跳转
    • 用goto 跳转到必须在当前函数内定义的标签
    • 标签名是大小写敏感的。
          func myFunc() {
              i := 0
          Here:   // 这行的第一个词,以冒号结束作为标签
              println(i)
              i++
              goto Here   // 跳转到 Here 去
          }
      
  • for
    • 循环读取数据
    • 当作while控制逻辑
          sum := 1
          for sum < 1000 {
              sum += sum
          }
      
    • 迭代操作
    • for 配合 range 可以用于读取 slice 和 map 的数据
    • break 和 continue 还可以跟着标号,用来跳到多重循环中的外层循环
    • 标号语句必须紧接在循环的头部。标号语句不能用在非循环语句的前面
  • switch
    • 表达式不必是常量或整数
    • 执行的过程从上至下,直到找到匹配项
    • 如果 switch 没有表达式,它会匹配 true。
    • switch 默认相当于每个 case 最后带有 break,匹配成功跳出整个switch,可以使用 fallthrough 强制执行后面的 case 代码。
          i := 10
          switch i {
          case 1:
              fmt.Println("i is equal to 1")
          case 2, 3, 4:
              fmt.Println("i is equal to 2, 3 or 4")
          case 10:
              fmt.Println("i is equal to 10")
              fallthrough
          default:
              fmt.Println("All I know is that i is an integer")
          }
      
  • func 函数
    • 支持多值返回,命名返回值,必须声明类型
    • 函数可以有一个或者多个参数,每个参数后面带有类型,通过,分隔
    • 可命名返回参数的变量,若函数是导出建议命名返回值
          func SumAndProduct(A, B int) (add int, Multiplied int) {
              add = A+B
              Multiplied = A*B
              return
          }
      
          // 支持变参
          func myfunc(arg ...int) {}
      
          type testInt func(int) bool // 声明了一个函数类型
      
    • 传值与传指针
      • 传参实际上是传值,其值可以是变量的值,也是可以是变量的地址,即指针
      • 变量在内存中是存放于一定地址上的,修改变量实际是修改变量地址处的内存
      • 传指针使得多个函数能操作同一个对象。
      • 传指针比较轻量级 (8bytes),只是传内存地址,指针传递体积大的结构体
      • 若用参数值传递的话, 在每次 copy 上面就会花费相对较多的系统开销(内存和时间)
      • Go 语言中 channel,slice,map这三种类型的实现机制类似指针,所以可以直接传递,而不用取地址后传递指针
    • defer
      • 多个defer调用 defer,那么 defer 是采用后进先出模式
      • defer 后指定的函数会在函数退出前调用
      • 当函数执行到最后时,这些 defer 语句会按照逆序执行,最后该函数返回。
    • 函数作为值类型
      • 写通用接口
    • panic Recover
    • main init
      • init 函数 能够应用于所有的 package,可选
      • main 函数(只能应用于 package main,必选)
      • 这两个函数在定义时不能有任何的参数和返回值。
      • 程序的初始化和执行都起始于 main 包
      • 流程
        1. main导入包
        2. 对导入包内的常量和变量进行初始化
        3. 执行导入包内的init函数
        4. 对main包中的包级常量和变量进行初始化,执行main包init,main函数
    • import
      • GOROOT 环境变量指定目录下去加载该模块
          // 当前文件同一目录的 model 目录,但是不建议这种方式来 import
          import "./model"
        
          // 绝对路径 加载 gopath/src/shorturl/model 模块
          import "shorturl/model" 
        
      • import 简化行为
        • 点 省略前缀的包名
        • 别名
        • _ 调用包里面的 init 函数
          import (
              // 即调用 fmt.Println("hello world") 可以省略的写成 Println("hello world")
              . "fmt"
          )
        
          import(
              // 即可 f.Println("hello world")
              f "fmt"
          )
        
          import (
              "database/sql"
              // 调用了该包内的init函数,但不对其它内容进行导入处理
              _ "github.com/ziutek/mymysql/godrv"
          )
        

struct类型

  • struct类型初始化

    • 按照顺序提供初始化值
    • 通过 field:value 的方式初始化,这样可以任意顺序
    • 通过 new 函数分配一个指针,此处P的类型为 *person
  • struct 的匿名字段(嵌入字段)

    • 匿名字段能够实现字段的继承
    • 所有的内置类型和自定义类型都可以作为匿名字段
    • 同名字段,外层的优先访问,可重载
          type Skills []string
    
          type Human struct {
              name string
              age int
              weight int
          }
    
          type Student struct {
              Human  // 匿名字段,那么默认 Student 就包含了 Human 的所有字段
              Skills // 匿名字段,自定义的类型 string slice
              int    // 内置类型作为匿名字段
              speciality string
          }
    
          func main() {
              // 我们初始化一个学生
              mark := Student{Human{"Mark", 25, 120}, "Computer Science"}
          }
    

面向对象

  • method

    • 定义:带有接收者的函数
          func (r ReceiverType) funcName(parameters) (results)
      
          // 自定义类型,类似于别名
          type typeName typeLiteral
          type ages int
          type months map[string]int
      
    • 可以在任何的自定义类型中定义任意多的 method
  • 指针作为receiver

    • go 知道是否调用指针的 method 还是非指针的 method,会自转
    • 如果一个 method 的 receiver 是 *T, 你可以在一个 T 类型的实例变量 V 上面调用method,而不需要 &V 去调用这个 method
  • method继承 vs 重写

interface类型

  • interface 是一组 method 签名的组合
  • 空interface
    • interface{} 存储任意类型的数值 (类C void*)
    • interface 函数参数
  • interface 变量存储的类型
    • Comma-ok 断言
      • value,ok = element(T)
      • element 为interface变量,T断言的类型
    • element.(type) 语法不能在switch外的任何逻辑里面使用
  • 嵌入interface
    • 相同的逻辑引入到interface内
          type Interface interface {
              sort.Interface // 嵌入字段 sort.Interface
              Push(x interface{}) // a Push method to push elements into the heap
              Pop() interface{} // a Pop elements that pops elements from the heap
          }
      
  • 反射
    • 反射某一类型的值(这些值都实现了空interface)
      1. 转化为reflect对象(reflect.Type 或 reflect.Value)
        t := reflect.TypeOf(i)    // 得到类型的元数据,通过t我们能获取类型定义里面的所有元素
        v := reflect.ValueOf(i)   // 得到实际的值,通过 v 我们获取存储在里面的值,还可以去改变值    
      
      1. 将reflect转化为相应的值
        tag := t.Elem().Field(0).Tag  // 获取定义在 struct 里面的标签
        name := v.Elem().Field(0).String()  // 获取存储在第一个字段里面的值
      
      1. 反射的字段必须是可修改(可读写)
        var x float64 = 3.4
        v := reflect.ValueOf(x)
      
        fmt.Println("type:", v.Type())
        fmt.Println("kind is float64:", v.Kind() == reflect.Float64)
        fmt.Println("value:", v.Float())
      
        //修改相应的值
        p := reflect.ValueOf(&x)
        v := p.Elem()
        v.SetFloat(7.1)
      

并发

  • goroutine

    • 并行程序设计,Go语言层面支持
    • goroutine 比线程更小,比thread更易用,高效,轻便
    • Go语言内部实现了goroutine之间的内存共享
    • goroutine 是通过 Go 的 runtime 管理的一个线程管理器
    • 不通过共享来通信,而通过通信来共享。
  • channels

    • 同goroutine 运行在相同的地址空间
    • 阻塞,也就是如果读取(value := <-ch)它将会被阻塞,直到有数据接收
    • 默认情况下,channel 接收和发送数据都是阻塞的,不需要显式的 lock
          ch <- v    // 发送 v 到 channel ch.
          v := <-ch  // 从 ch 中接收数据,并赋值给v
      
  • Buffered Channels

    • go 允许指定channel缓冲大小,即channel可存储的元素
    • 在有缓冲的情况下,缓冲数之下,元素可以无阻塞写入通道,超过代码会阻塞,直到有其它goroutine从channel中读取一些元素,让出空间
  • Range 和 Close

    • for i := range c 能够不断的读取 channel 里面的数据,直到该 channel 被显式的close关闭
    • v,ok := <-ch 测试channel是否被关闭
    • 在生产者的地方关闭 channel
  • 多个channel

    • select 默认阻塞,监听channel,随机选择一个执行
  • 超时

    • 避免整个程序进入阻塞方案
      • 用 select 监听来设置超时
  • runtime goroutime

    • Goexit
      • 退出当前执行的 goroutine,但是 defer 函数还会继续调用
    • Gosched
      • 让出当前 goroutine 的执行权限,调度器安排其他等待的任务运行,并在下次某个时候从该位置恢复执行
    • NumCPU
      • 返回 CPU 核数量
    • NumGoroutine
      • 返回正在执行和排队的任务总数
    • GOMAXPROCS
      • 用来设置可以并行计算的 CPU 核数的最大值,并返回之前的值。

golang关键字小结

  • defer 用于类似析构函数
  • go 用于并发
  • select 用于选择不同类型的通讯
  • interface 用于定义接口
  • struct 用于定义抽象数据类型
  • chan 用于 channel 通讯
  • type 用于声明自定义类型
  • map 用于声明 map 类型数据
  • range 用于读取 slice、map、channel 数据
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值