推荐使用Gogland
或者IntelliJ IDEA
安装golang
插件,其他的sublime text
或者vs code
都可以,选择自己熟悉的开发工具就OK~
scorpio
工程是核心代码,与业务相关的所有代码都放置在该工程下面starjazz-go
工程是项目用到到所有公共代码,包括第三方包(包括用go get
命令安装)都放置在该工程下面
- 进入
scorpio
目录,执行setup-gopath.sh
脚本,该脚本会把当前目录和starjazz-go
项目设置为gopath
- 提交代码之前先手动执行
format-src.sh
脚本,该脚本会用golang
的标准方式格式化代码 - 也可以直接在
git
本地的pre-commit
的hook
文件中加上上面格式化的脚本,避免每次手动执行
- 可以在
scorpio
根目录中新建一个bin
文件夹 - 进入
bin
文件夹,执行命令go build scorpio/mathapp
- 在
bin
目录下面会生成一个mathapp
的可执行文件,执行命令./mathapp
即可得到运行结果 - 也可以直接在
scorpio
根目录下面直接执行命令go run src/scorpio/mathapp/main.go
得到运行结果
代码路径:pointers.go
Go
具有指针。 指针保存了变量的内存地址。
类型 *T
是指向类型 T
的值的指针。其零值是 nil
。
var p *int
&
符号会生成一个指向其作用对象的指针。
i := 42
p = &i
*
符号表示指针指向的底层的值。
fmt.Println(*p) // 通过指针 p 读取 i
*p = 21 // 通过指针 p 设置 i
这也就是通常所说的“间接引用”或“非直接引用”。
与 C
不同,Go
没有指针运算。
代码路径:structs.go
一个结构体(struct
)就是一个字段的集合。
(而 type
的含义跟其字面意思相符。)
结构体字段使用点号来访问。
结构体字段可以通过结构体指针来访问,通过指针间接的访问是透明的。
代码路径:array.go
类型[n]T
是一个n
个类型为T
的值的数组。
var a [10]int
定义变量a
是一个有10个整数的数组。
数组的长度是其类型的一部分,因此数组不能改变大小。
一个slice
会指向一个序列的值,并且包含了长度信息。
[]T
是一个元素类型为T
的slice
。
slice
可以重新切片,创建一个新的slice
值指向相同的数组。
s[lo:hi]
:表示从lo
到hi-1
的slice
元素,含两端。
因此s[lo:lo]
是空的,而s[lo:lo+1]
有一个元素。
slice
由函数make
创建。这会分配一个零长度的数组并且返回一个slice
指向这个数组:
a := make([]int, 5) // len(a)=5
为了指定容量,可以传递第三个参数到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
slice
的零值是nil
,一个nil
的slice长度和容量是0
。
向slice
添加元素是一种常见的操作,Go
提供了一个内建的append
函数。
func append(s []T, vs ...T) []T
append
的第一个参数s
是一个类型为T
的数组,其余类型为T
的值将会添加到slice
上。
append
的结果是一个包含原slice
所有元素加上新添加的元素的slice
。
如果s
的底层数组太小,而不能容纳所有的值时,会分配一个更大的数组。返回的slice
会指向这个新分配的数组。
参阅slice
文章:使用和内幕
代码路径:interfaces.go
Go
语言没有类和几成的概念。但是Go
语言有非常灵活的接口概念,通过它可以实现很多面向对象的特性。
接口提供了一种方式来说明对象的行为。
接口定义了一组方法集,但是这些方法不包含(实现代码):它们没有被实现(它们是抽象的)。接口里也不能包含变量。
有的时候,也会以一种稍微不同的方式来使用接口这个词:从某个类型的角度来看,它的接口指的是:它的所有导出方法,只不过没有显式地为这些导出方法额外定一个接口而已。
一个接口可以包含一个或者多个其他的接口,这相当于直接将这些内嵌接口的方法列举在外层接口中一样。
比如接口File
包含了ReadWrite
和Lock
的所有方法,它还额外有一个Close
方法。
type ReadWrite interface {
Read(b Buffer) bool
Write(b Buffer) bool
}
type Lock interface {
Lock()
Unlock()
}
type File interface {
ReadWrite
Lock
Close()
}
一个接口类型的变量varI
中可以包含任何类型的值,必须有一种方式来检测它的动态类型,即运行时在变量中存储的值的实际类型。
在执行过程中动态类型可能会有所不同,但是它总是可以分配给接口变量本省的类型。通常我们可以使用类型断言来测试在某个时刻varI
是否包含类型T
的值:
v := varI.(T) // unchecked type assertion
varI 必须是一个接口变量,否则编译器会报错:invalid type assertion: varI.(T) (non-interface type (type of varI) on left)
。
类型断言可能是无效的,虽然编译器会尽力检查转换是否有效,但是它不可能预见所有的可能性。如果转换在程序运行时失败会导致错误发生。更安全的方式是使用以下形式来进行类型断言:
if v, ok := varI.(T); ok { // checked type assertion
Process(v)
return
}
// varI is not of type T
如果转换合法,v
是varI
转换到类型T
的值,ok
会是true
;否则v
是类型T
的零值,ok
是false
,也没有运行时错误发生。
应该总是使用上面的方式来进行类型断言。
gRPC
是一个高性能、通用的开源RPC框架,其由Google
主要面向移动应用开发并基于HTTP/2
协议标准而设计,基于ProtoBuf(Protocol Buffers)
序列化协议开发,且支持众多开发语言。
gRPC
提供了一种简单的方法来精确地定义服务和为iOS
、Android
和后台支持服务自动生成可靠性很强的客户端功能库。客户端充分利用高级流和链接功能,从而有助于节省带宽、降低的TCP
链接次数、节省CPU
使用、和电池寿命。
我们可以从这里http://www.grpc.io/blog/principles gRPC
的动机和设计原则。