How to Write Go Code
官方How to Write Go Code的阉割版 :-D
GOPATH
GOPATH环境变量指明当前工作区的位置, 这可能在你编写Go程序时唯一一个需要设置的环境变量
|
|
Go命令
go install第一步先生成结果文件(可执行文件或者.a包), 第二步会把编译好的结果移到$GOPATH/pkg或者$GOPATH/bin
|
|
go build主要用于编译代码
|
|
go继承轻量级测试, 测试文件的文件名为*_test.go的形式, 其中函数命名为func TestXXX(t *testing.T), 如果函数调用失败的函数, 如t.Error或者t.Fail, 则认为这个测试用例失败
|
|
go语言有一个获取远程包的工具就是go get(类似于pip install),目前go get支持多数开源社区(例如: github、googlecode、bitbucket、Launchpad)
|
|
go get -u参数可以自动更新包,而且当go get的时候会自动获取该包依赖的其他第三方包
命名
- package后的包名使用小写, 不需要使用大小写混用或者下划线
- 自定义Get和Set方法时(Go不提供自动支持), 如果owner是个结构体, Get方法可以命名为
Owner, Set方法命名为SetOwner - 接口命名应该以
er为后缀 - 大写字母开头的变量是可导出的, 也就是其它包可以读取的, 是
公有变量, 小写字母开头的就是不可导出的,是私有变量 - 大写字母开头的函数也是一样, 相当于class中的带public关键词的
公有函数, 小写字母开头的就是有private关键词的私有函数。
资源分配
new是一个用来分配内存的内建函数,但是不像在其它语言中, 它并不初始化内存, 只是将其置零. 也就是说, new(T)会为T类型的新项目, 分配被置零的存储, 并且返回它的地址, 一个类型为*T的值. 在Go的术语中, 其返回一个指向新分配的类型为T, 值为零的指针
表达式
new(Type)和&Type{}是等价的
- 内建函数
make(T, args)与new(T)的用途不一样. 它只用来创建slice、map和channel, 并且返回一个初始化的(而不是置零), 类型为T的值(而不是*T), 导致这三个类型有所不同的原因是指向数据结构的引用在使用前必须被初始化. 对于slice、map和channel来说, make初始化了内部的数据结构, 填充适当的值.
方法
任何命名类型(指针和接口除外)都可以定义方法(方法不是函数), 此时这个类型被称为接收器(receiver).
- 当接收器为值类型时, 方法对值的改变外部无法感知.
|
|
- 当接收器为指针时, 方法内部可以对接收器作修改, 外部可以感知.
|
|
接口
interface是一组method
签名的组合
- 任意的类型都实现了
空interface(类型为interface{}),空interface作为函数参数时, 表示可以传入任意类型的变量 一个类型不需要明确的声明它实现了某个接口.一个类型要实现某个接口, 只需要实现该接口对应的方法就可以了. 在实际中, 多数接口的类型转换和检查都是在编译阶段静态完成的. 例如, 将一个*os.File类型传入一个接受io.Reader类型参数的函数时, 只有在*os.File实现了io.Reader接口时,才能编译通过
假设我们只是想知道某个类型是否实现了某个接口, 而实际上并不需要使用这个接口本身 —— 例如在一段错误检查代码中—— 那么可以使用空白标识符(_)来忽略类型断言的返回值:
|
|
- 反向获取interface变量里面实际保存了的是哪个类型的对象
|
|
并发
goroutine运行在相同的地址空间, 而Go以channel通信的方式来实现共享变量,
- 无缓冲区channel(
make(chan int)), 只能想channel中传入一个数据, 此时传入第二个数据会阻塞, 必须等第一个被取出, 第二个数据才能成功传入 - 有缓冲区channel(
make(chan int, 5)). 前五个数据可以无阻塞的传入, 第六个数据必须等前五个数据中的某个数据被取走才能成功传入, 否则会阻塞在哪里. - channel的阻塞机制可以考虑与阻塞socket对应的读写缓冲区对比.
|
|
<-c会一直阻塞, 直到有数据可以从channel中取出.
在目前的Go runtime 实现中, goroutine代码在默认情况下是不会被并行化的。对于用户态任务, 默认仅提供一个物理CPU进行处理. 任意数目的goroutine可以阻塞在系统调用上, 但默认情况下, 在任意时刻,只有一个goroutine可以被调度执行. 未来go语言的设计可能更加智能, 但是目前, 必须通过设置
GOMAXPROCS环境变量或者导入runtime包并调用runtime.GOMAXPROCS(NCPU), 来告诉Go的运行时系统最大并行执行的Goroutine数目. 可以通过runtime.NumCPU()获得当前运行系统的逻辑核数, 作为一个有用的参考.
- 当存在多个channel时, 使用select监听channel上的数据流动
select默认是阻塞的, 只有当监听的channel中有发送或接收可以进行时才会运行, 当多个channel都准备好的时候, select是随机的选择一个执行的
|
|