public:it:go

这是本文档旧的修订版!


Go Lang

  • 了解该语言的出生背景与适用环境
  • 了解输入输入出流,文件流操作
    • 打印:
      fmt.Println("i's value is ", i)
      fmt.Printf("i's type is %T, i's value is %v \n", i, i)

      格式文档:fmt

  • 了解程序代码和可执行代码的组织机制,运行时模块加载、符号查找机制
    • 主程序入口 package main;
    • 包管理,导入包使用 import, 可单导入 import “fmt”, 也可多导入 import (“fmt”;“math/rand”);
    • 包名与导入路径的最后一个元素一致 import “math/rand”; rand.xxx;
  • 了解该语言的基本数据类型,基本语法和主要语言构造,主要数学运算符和输入输出函数的使用
    • 首字母大写为已导出名
    • 声明时类型后置,例如 func add(x int, y int) int, 后置原因:关于go的声明语法
    • 类型相同的声明可只留最后一个,例如 func add(x, y int) int
    • 变量声明 var a, b, c bool
    • 变量声明可有初始值,有初始值时可省略类型:
       var a, b, c = true, 10, 'hello!' 
    • 变量无初始值时将初始为零值0,false“”
    • 在函数内时,变量声明可用:= 来省略 var:
       a, b, c := true, 10, 'hello!'
    • 基本类型:
      bool
      string
      int  int8  int16  int32  int64
      uint uint8 uint16 uint32 uint64 uintptr
      byte // uint8 的别名
      rune // int32 的别名 表示一个 Unicode 码点
      float32 float64
      complex64 complex128
    • 类型转换必须显式转换 T(x)
      var f float64 = 3.14
      var i int = int(f)
    • 常量定义:const Pi = 3.14
    • for循环,没有小括号
      for i := 0; i < 10; i++ {
          sum += i
      } 

      可省略

      sum := 0
      for ; sum < 10; {
          sum += sum
      }

      可进一步省略(形似while, go语言没有while)

      sum := 0
      for sum < 10 {
          sum += sum
      }

      进一步无限循环

      for {
      }
    • if也没有小括号,并且可类似 for 在条件表达式前有一个简单语句, 作用域延伸至else
      if v := math.Pow(2, 10); v < 1000{
          fmt.Println(v)
      } else {
          fmt.Println("%v < 1000", v)
      }
    • switch 语法, case 默认自带 break, 不会往下一个 case 走,除非显式调用 fallthrough
    • case 可带变量或表达式。从上到下顺次执行,一旦匹配成功时停止,不会执行之后的case表达式(除非 fallthrough)。
    • switch省略表达式时,等同于 switch true, 这种形式能将一长串 if-then-else 写得更漂亮
      t := time.Now()
      switch {
      case t.Hour() < 12:
          fmt.Println("Good morning!")
      case t.Hour() < 17:
          fmt.Println("Good afternoon.")
      default:
          fmt.Println("Good evening.")
      }
    • go 拥有指针 var p *int = &i, 指针零值为 nil, go没有指针运算。
    • go 结构体 struct 与 C/C++ 类似。 结构体指针可直接用点号获取结构字段值 p.X
  • 了解数组和其他集合类的使用
    • 数组array的声明 var a [10]int,操作类似C语言。长度必须声明且不能改变。
    • 长度为空时的声明是数组切片,切片(slice)可理解为数组部分区间的引用 var s []int = a[1:4], 范围左闭右开。范围可缺省,a[:],等价于 a[0:10]
    • 切片拥有 长度len(s) 和 容量 cap(s), 可以通过重新切片来扩展一个切片的容量s = s[:0]
      • 切片的长度就是它所包含的元素个数。
      • 切片的容量是从它的第一个元素开始数,到其底层数组元素末尾的个数。
    • 切片空值为 nil
    • make 来创建“动态”数组, make 函数会分配一个元素为零值的数组并返回一个引用了它的切片
      b := make([]int, 0, 5) // len(b)=0, cap(b)=5
      b = b[:cap(b)] // len(b)=5, cap(b)=5
      b = b[1:]      // len(b)=4, cap(b)=4
    • append 函数来追加切片元素,当底层数组长度不够时,append会默认分配更长的数组并指给切片。
    • range 配合 for 循环切片
      var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}
      for i, v := range pow {
          fmt.Printf("2**%d = %d\n", i, v)
      }

      第一个变量i表示下标,第二个v标识值,可用_来忽略其中一个:for _, v := range pow,或只留一个变量来表示下标for i := range pow

    • map 的声明 var m map[string]int, 可用 make 初始化 m := make(map[string]int)
    • map 赋值 m[key] = elem; 获取 elem = m[key]; 删除 delete(m, key)
    • map 双赋值
      elem, ok = m[key]

      若 key 在 m 中,ok 为 true ;否则,ok 为 false, elem 为该值类型的零值。

  • 了解字符串的处理
  • 了解该语言在面向对象,函数式编程,泛型,元编程等编程范式的特性
    • 函数(func)也为值,可传递,可作为参数与返回值
  • 了解特有的语法糖
    • 多值返回,函数可返回任意数量返回值,也可对返回值命名 func split(sum int) (x, y int),没有参数的 return 语句返回已命名的返回值。
    • defer 语句会将函数推迟到外层函数返回之后执行。推迟调用的函数其参数会立即求值,但直到外层函数返回前该函数都不会被调用。
  • 了解该语言错误处理,调试方式以及对测试的支持
  • 了解该语言的内存分配机制或GC,线程,进程等运行时效率相关
  • 了解该语言的编译/解释机制
  • How goroutines work :

    Go 运行时负责调度 Goroutines。Goroutines 的调度是协作式的,而线程不是。

    这意味着每次一个线程发生切换,你都需要保存/恢 复所有寄存器,包括16个通用寄存器、PC (程序计数器)、SP(栈指针)、段寄存器( segment register )、16个 XMM 寄存器、FP 协处理器状态、X AVX 寄存器以及所有 MSR 等。

    而当另一个 Goroutine 被调度时,只需要保存/恢复三个寄存器,分别是 PC、SP 和 DX。

    Go 调度器和任何现代操作 系统的调度器都是 O(1) 复杂度的,这意味着增加线程 /goroutines 的数量不会增加切换时间,但改变寄存器的代价是不可忽视的。

    • 在Go 1.4 之前, 当创建一个goroutine时,Go运行时会分配一段8K字节的内存用于栈供goroutine运行使用, 如果不够, 则使用分段栈(Segmented Stacks)来扩展
    • 分段栈(Segmented Stacks)方式, 在栈缩小时的操作代价比较高(要频繁处理分段间的跨越).
    • 在Go 1.4 中, 使用栈拷贝(stack copying)方式来处理栈伸缩, 新方案创建一个两倍于原stack大小的新stack,并将旧栈拷贝到其中。这意味着当栈实际使用的空间缩小为原先的大小时,go不用做额外操作,此时栈缩小是一个无任何代价的操作。
    • 栈拷贝需把原栈指针重定向,而获取原栈指针依靠的是垃圾回收机制(会记录栈指针).但是使用C代码写的运行时调用不参与go的垃圾回收机制, 将会缺失栈指针信息而使用老机制(分段栈)
  • public/it/go.1639114467.txt.gz
  • 最后更改: 2021/12/10 13:34
  • oakfire