Go笔记归档

一、Go语言基本语法

1.包

  1. package

  2. import

  3. 从main包的main方法开始

  4. 没有public、protected、private等访问控制修饰符,它是通过字母大小写来控制可见性的,如果定义的常量、变量、类型、接口、结构、函数等的名称是大写字母开头表示能被其它包访问或调用(相当于public),非大写开头就只能在包内使用(相当于private,变量或常量也可以下划线开头)

  5. 根据文件路径来判断包

2.函数

  1. 当连续两个或多个函数的已命名形参类型相同时,除最后一个类型以外,其它都可以省略。 x, y int

  2. 多值返回

    • a,b := 4,5
  3. 命名返回值

    • func split(sum int) (x, y int)

3.var变量

  1. 可以出现在包的级别,也可以出现在func里

  2. 可以一起初始化,可以不指定类型

    • var java, c, test = 1, “dfer”, true
  3. 简洁赋值语句 := 可在类型明确的地方代替 var 声明。但不能出现在函数外

4.const常量

5.类型

  1. 基本类型

    • bool
    • string
    • int int8 int16 int 32 int64
    • uint uint8 uint16 uint32 uint64 uintptr
    • byte == uint8
    • rune == int32表示一个unicode码点
    • float32 float64
    • complex64 complex128
  2. 类型自动推导

  3. 类型转换

    • Go 在不同类型的项之间赋值时需要显式转换。
    • string转成int int, err := strconv.Atoi(str)
    • int -> string string := strconv.Itoa(int)
    • string -> []byte var data []byte = []byte(str)
    • []byte -> string var str string = string(data[:])
    • float64 <-> string float,err := strconv.ParseFloat(string,64) string := strconv.FormatFloat(float64,’E’,-1,64)

6.流程控制

  1. 只有一种循环模式 for

    • for ; sum < 1000; {}
    • for sum < 1000 跟其他语言的while一模一样
    • for {} 死循环
    • for index, value := range arrOrMap {
      }
      • for _,value := rang arrOrMap{} 用_忽略index或者值
  2. if else

    • if 也可以在执行判断前,先执行一个语句
      • if z:=x+y; z<a {
        }
  3. switch

    • 相当于自带break, 除非指定fallthrough,否则不会继续执行
    • 也可以在执行前,先执行一个语句
      • switch v:=x+y; v {}
    • 没有条件的switch == switch true 可以将一长串if else写得很清晰
      • switch{ case t.Hour() < 12: …}
  4. defer

  • defer 语句会推迟到外层函数返回之后执行。但其参数会立即求值,只是返回前不会调用
  • defer的调用是被压入了栈中,会按后进先出的顺序调用

7.更多类型

  1. 指针

    • *int 指向int类型的值的指针
    • *p 读取p指针指向的位置
    • &i 获取变量i的指针
    • 跟C不同 没有指针运算
  2. struct

    1
    2
    3
    4
    type duck struct {
    X int
    Y int
    }
  • d := duck{1,2}
  • d.X
  • 如果我们有一个指向结构体的指针 p,那么可以通过 (*p).X 来访问其字段 X。直接写 p.X 就可以。
  • 可以按名字赋值 duck{X:1}
  1. 数组

    • var a [10]int
    • v := [5]int{1,2,3,4,5}
  2. 切片类型 slice

    • v := arr[1:4], 闭开区间,从下标1到4,不包括4
    • var s []int 切片的语法跟数组的区别就在于没有指定长度
    • 切片是原来数组的引用,对切片操作会反应在原来数组上。
    • 默认切片 a[0:10] a[:10] a[0:] a[:] 对于长度为10的数组是等价的
    • slice s len(s) 切片长度 cap(s) 切片的第一个到最后一个的长度
    • var s []int 默认值为nil
    • make([]int, 0, 5) make([]int, 5)
      • make只用于slice, map, channel的创建
      • 和new不同的是,make的返回值是一个类型,而不是指向它的指针
    • 向切片追加元素 append ([]T, ….T)
      • 当 s 的底层数组太小,不足以容纳所有给定的值时,它就会分配一个更大的数组。返回的切片会指向这个新分配的数组
  3. map

    • var m map[keyType]ValueType
    • make(map[int]string)
    • m[1] = “test”
    • m := map[int]duck{ 1:duck{1,2}, 2:duck{4,5}, }
    • delete(m, key)
    • elem, ok = m[key]
      • 若 key 在 m 中,ok 为 true ;否则,ok 为 false。
  4. func函数也可以当参数传递

  • 闭包(closure)就像是对作用域的一种闭合(closing),在函数定义的时候,其作用域已经决定了,并且后续使用不会再改变,即作用域已经闭合了。
    • 每个闭包都被绑定在其各自的变量上。闭的意思是封闭外部状态,当外部状态的scope失效的嘶吼,留了一份留在内部
    • 可以理解成在闭包创建时,把引用的变量的值拷贝了一份。以此实现内外环境的隔离。
    • func adder() func(int) int { sum := 0 return func(x int) int { sum += x return sum } } func main() { pos, neg := adder(), adder() for i := 0; i < 10; i++ { fmt.Println( pos(i), neg(-2*i), ) } }
    • 闭包是函数式的基本配备。
    • Go Routine的延迟绑定
  1. OOP:方法与接口
  • 方法就是一类带特殊的 接收者 参数的函数。

    • func (v Vertex) Abs() float64 {} v.Abs()
    • 方法只是个带接收者参数的函数。
    • 可以为非结构体类型声明方法。 type Myfloat float64
    • 用指针来接收 会更常用 可以改变对象的值
      • func (v *Vertex) Scale(f float64) { v.X = v.X * f v.Y = v.Y * f }
        • 用指针定义好处一:方法能够修改其接收者指向的值。
        • 这样可以避免在每次调用方法时复制该值。若值的类型为大型结构体时,这样做会更加高效。
    • 作为方法调用时,可以用指针也可以用对象来调用 v.Scale(2) or (&v).Scale(2) 不管定义的时候是用指针还是值
  • 接口

    • type Abser interface { Abs() float64 }
    • 类型通过实现一个接口的所有方法来实现该接口。无需专门显式声明
    • 指定了零个方法的接口值被称为 空接口 interface{}
      • 空接口可保存任何类型的值。(因为每个类型都至少实现了零个方法。)
      • 空接口被用来处理未知类型的值
  • 类型判断和转换 scala里的isInstanceOf 和asInstanceOf

    • t, ok := i.(T) 相当于同时做isInstanceOf和asInstanceOf的操作,失败了也不会panic
    • t := i.(T) 相当于asInstanceOf,失败了会panic
    • switch + type来选择类型 相当于一连串的if else 判断isInstanceOf + asInstanceOf
      • switch v := i.(type) { case int: … case string: len(v) // v已经可当string用了 default: }
  • error 类型是一个内建接口 Error() string

    • 自定义的error只要实现这个Error接口就可以了
    • errors.New

二、协程与并发

  • Go 协程在相同的地址空间中运行,因此在访问共享的内存时必须进行同步。sync 包提供了这种能力,不过在 Go 中并不经常用到
    • go f(x, y, z) f, x, y 和 z 的求值发生在当前的 Go 程中,而 f 的执行发生在新的 Go 程中。
  • ch <- v // 将 v 发送至信道 ch。 v := <-ch // 从 ch 接收值并赋予 v。 v, ok := <-ch //从ch接收值,如果已被关闭,ok会为false
  • select - case 语句使一个 Go 程可以等待多个通信操作。
    • select - case - default 当 select 中的其它分支都没有准备好时,default 分支就会执行。 为了在尝试发送或者接收时不发生阻塞,可使用 default 分支
  • sync.Mutex
  • .Lock()
  • .Unlock()

三、Go语言关键特性

  1. 并发与协程

    • 一个关键字go就可以启动协程
  2. 基于消息传递的通信方式

    • 传统的是基于共享内存,go用消息管道channel,关键字chan 类型
  3. 丰富的内置数据类型

    • slice
    • channel
    • rune == int32表示一个unicode码点
    • uintptr 存储指针的uint32或者uint64
    • struct + interface + function 没有 class
  4. 函数多返回值

  5. defer机制

  6. 反射

  7. 高性能HTTP Server

    • 自带HTTP/TCP/UDP高性能服务器,基于协程并发
  8. 工程管理

    • 完全用目录结构和包名来推导工程结构和构建顺序
      • 同一个目录下面只允许一个包, 就算定义在不同的文件里,相当于同一个文件 package中的名称最好与目录名一样
    • 编译不需要任何依赖
      • 编译生成后的二进制文件运行起来无环境依赖
    • 编译速度快
  9. 编程规范

    • 自动统一的code style格式化
  10. Error 处理

    • error
    • panic & recover
  11. 面向接口的oop,没有对象与继承,强调组合,以类似于duck-typing的方式编写面向对象

    • 当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。我们并不关心对象是什么类型,到底是不是鸭子,只关心行为。
    • 没有类、继承、构造方法、泛型、注解,理解代码变得更容易

四、Go语言的特点

  1. 开发效率高

    • 语言简单,容易上手
      • 仅25个关键字
    • 编译快
    • 部署运维简单
      • 不需要额外安装像java的jdk或者js的node这样的运行环境
      • 构建好后只需一个可执行文件即可
  2. 高并发

    • Gorountine 协程机制
      • 轻量级 比线程更轻量级
        • 协程与线程主要区别是它将不再被内核调度,而是交给了程序自己而线程是将自己交给内核调度,所以也不难理解golang中调度器的存在。
        • 进程是系统分配资源的最小单位 线程是CPU调度的最小单位(共享进程的内存地址空间) 协没有线程的上下文切换消耗。协程的调度切换是用户(程序员)手动切换的,因此更加灵活,因此又叫用户空间线程.有原子操作性
      • 可以产生大量协程
  3. 高性能

    • 运算性能是JAVA的1.5倍左右,运行空间是JAVA的几十分之一,启动时间是JAVA的几十分之一,并发量是JAVA的上千倍
    • 从性能上不如C语言,但是语法上比C要更加“现代化”一些。C语言是纯过程性语言,申请内存,分配内存都需要手工处理,而GO语言支持简单的自动化GC。

五、其他信息

  1. 国内并发需求很大,对Go的需求一直在上升

  2. Go语言的核心理念

    • 简单
      • 比如及其简单但完备的面向对象设计,面向接口,没有继承只有组合
    • 正交性
      • 每个模块之间互相不影响,或者说互相不知道。改了一个不会影响另外一个
        • Go语言最有价值的地方是对现有OOP的改进,现在无论什么语言只要支持OOP就一定会有一个庞大的继承树,但是无论这个树设计的多庞大多精巧它仍然是一个静态的结构,一旦和实际问题不匹配就要写一堆Adapter。 而Go语言采用完全不用的方法,类之间不存在静态的继承或者实现关系,这种关系直到使用它的时候才确定
  3. 工具

    • GoFmt自动格式化工具

六、常用方法

  1. fmt.Printf

    • %T 数据类型
    • %v 按默认方式打印
    • int
      • %+d 带符号的
      • %q带引号
      • %o %x八进制十六进制
      • %u unicode
      • %b 二进制
      • %5d %-5d %05d
    • float
      • %f == %.6f
      • %e == %.6e
      • %g 用最少的数字来表示
      • %.3g最多三个数字来表示
    • string
      • %s正常输出
      • %q 带双引号
      • %x %X 16进制
      • %5s %-5s %.5s %5.7s %05s
    • bool
      • %t true or false
    • pointer
      • %p 带0x的指针
      • %#p 不带0x的指针
  2. fmt.Stringer

    • 最常用的interface, 定义了 String() string 类似于java的toString 方法
  3. time

    • time.Saturday
    • time.Now() 是time.Time类型的一个实例
      • time.Now().Weekday()
      • time.Now().Hour()
    • time.Sleep(1 * time.Second)
    • time.After 相当于js里的setTimeout time.Tick 返回一个时间类型的channel. 相当于js 里的setInterval 每隔一段时间执行送入channel
  4. runtime

    • runtime.GOOS os信息
  5. strings

    • strings.Join(arr, “,”)
    • strings.NewReader(str) 产生io.Reader对象 数据流
  6. strconv

    • AtoI, Itoa FormatInt, ParseInt FormatFloat, ParseFloat, FormatUint

六、尾巴