Go笔记归档
一、Go语言基本语法
1.包
package
import
从main包的main方法开始
没有public、protected、private等访问控制修饰符,它是通过字母大小写来控制可见性的,如果定义的常量、变量、类型、接口、结构、函数等的名称是大写字母开头表示能被其它包访问或调用(相当于public),非大写开头就只能在包内使用(相当于private,变量或常量也可以下划线开头)
根据文件路径来判断包
2.函数
当连续两个或多个函数的已命名形参类型相同时,除最后一个类型以外,其它都可以省略。 x, y int
多值返回
- a,b := 4,5
命名返回值
- func split(sum int) (x, y int)
3.var变量
可以出现在包的级别,也可以出现在func里
可以一起初始化,可以不指定类型
- var java, c, test = 1, “dfer”, true
简洁赋值语句 := 可在类型明确的地方代替 var 声明。但不能出现在函数外
4.const常量
5.类型
基本类型
- bool
- string
- int int8 int16 int 32 int64
- uint uint8 uint16 uint32 uint64 uintptr
- byte == uint8
- rune == int32表示一个unicode码点
- float32 float64
- complex64 complex128
类型自动推导
类型转换
- 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.流程控制
只有一种循环模式 for
- for ; sum < 1000; {}
- for sum < 1000 跟其他语言的while一模一样
- for {} 死循环
- for index, value := range arrOrMap {
}- for _,value := rang arrOrMap{} 用_忽略index或者值
if else
- if 也可以在执行判断前,先执行一个语句
- if z:=x+y; z<a {
}
- if z:=x+y; z<a {
- if 也可以在执行判断前,先执行一个语句
switch
- 相当于自带break, 除非指定fallthrough,否则不会继续执行
- 也可以在执行前,先执行一个语句
- switch v:=x+y; v {}
- 没有条件的switch == switch true 可以将一长串if else写得很清晰
- switch{ case t.Hour() < 12: …}
defer
- defer 语句会推迟到外层函数返回之后执行。但其参数会立即求值,只是返回前不会调用
- defer的调用是被压入了栈中,会按后进先出的顺序调用
7.更多类型
指针
- *int 指向int类型的值的指针
- *p 读取p指针指向的位置
- &i 获取变量i的指针
- 跟C不同 没有指针运算
struct
1
2
3
4type duck struct {
X int
Y int
}
- d := duck{1,2}
- d.X
- 如果我们有一个指向结构体的指针 p,那么可以通过 (*p).X 来访问其字段 X。直接写 p.X 就可以。
- 可以按名字赋值 duck{X:1}
数组
- var a [10]int
- v := [5]int{1,2,3,4,5}
切片类型 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 的底层数组太小,不足以容纳所有给定的值时,它就会分配一个更大的数组。返回的切片会指向这个新分配的数组
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。
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的延迟绑定
- 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 }
- 用指针定义好处一:方法能够修改其接收者指向的值。
- 这样可以避免在每次调用方法时复制该值。若值的类型为大型结构体时,这样做会更加高效。
- 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语言关键特性
并发与协程
- 一个关键字go就可以启动协程
基于消息传递的通信方式
- 传统的是基于共享内存,go用消息管道channel,关键字chan 类型
丰富的内置数据类型
- slice
- channel
- rune == int32表示一个unicode码点
- uintptr 存储指针的uint32或者uint64
- struct + interface + function 没有 class
函数多返回值
defer机制
反射
高性能HTTP Server
- 自带HTTP/TCP/UDP高性能服务器,基于协程并发
工程管理
- 完全用目录结构和包名来推导工程结构和构建顺序
- 同一个目录下面只允许一个包, 就算定义在不同的文件里,相当于同一个文件 package中的名称最好与目录名一样
- 编译不需要任何依赖
- 编译生成后的二进制文件运行起来无环境依赖
- 编译速度快
- 完全用目录结构和包名来推导工程结构和构建顺序
编程规范
- 自动统一的code style格式化
Error 处理
- error
- panic & recover
面向接口的oop,没有对象与继承,强调组合,以类似于duck-typing的方式编写面向对象
- 当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。我们并不关心对象是什么类型,到底是不是鸭子,只关心行为。
- 没有类、继承、构造方法、泛型、注解,理解代码变得更容易
四、Go语言的特点
开发效率高
- 语言简单,容易上手
- 仅25个关键字
- 编译快
- 部署运维简单
- 不需要额外安装像java的jdk或者js的node这样的运行环境
- 构建好后只需一个可执行文件即可
- 语言简单,容易上手
高并发
- Gorountine 协程机制
- 轻量级 比线程更轻量级
- 协程与线程主要区别是它将不再被内核调度,而是交给了程序自己而线程是将自己交给内核调度,所以也不难理解golang中调度器的存在。
- 进程是系统分配资源的最小单位 线程是CPU调度的最小单位(共享进程的内存地址空间) 协没有线程的上下文切换消耗。协程的调度切换是用户(程序员)手动切换的,因此更加灵活,因此又叫用户空间线程.有原子操作性
- 可以产生大量协程
- 轻量级 比线程更轻量级
- Gorountine 协程机制
高性能
- 运算性能是JAVA的1.5倍左右,运行空间是JAVA的几十分之一,启动时间是JAVA的几十分之一,并发量是JAVA的上千倍
- 从性能上不如C语言,但是语法上比C要更加“现代化”一些。C语言是纯过程性语言,申请内存,分配内存都需要手工处理,而GO语言支持简单的自动化GC。
五、其他信息
国内并发需求很大,对Go的需求一直在上升
Go语言的核心理念
- 简单
- 比如及其简单但完备的面向对象设计,面向接口,没有继承只有组合
- 正交性
- 每个模块之间互相不影响,或者说互相不知道。改了一个不会影响另外一个
- Go语言最有价值的地方是对现有OOP的改进,现在无论什么语言只要支持OOP就一定会有一个庞大的继承树,但是无论这个树设计的多庞大多精巧它仍然是一个静态的结构,一旦和实际问题不匹配就要写一堆Adapter。 而Go语言采用完全不用的方法,类之间不存在静态的继承或者实现关系,这种关系直到使用它的时候才确定
- 每个模块之间互相不影响,或者说互相不知道。改了一个不会影响另外一个
- 简单
工具
- GoFmt自动格式化工具
六、常用方法
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的指针
fmt.Stringer
- 最常用的interface, 定义了 String() string 类似于java的toString 方法
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
runtime
- runtime.GOOS os信息
strings
- strings.Join(arr, “,”)
- strings.NewReader(str) 产生io.Reader对象 数据流
strconv
- AtoI, Itoa FormatInt, ParseInt FormatFloat, ParseFloat, FormatUint