- go语言作为开源社区最活跃的语言之一,其在并发性方面有着突出的优势,paas云计算中炙手可热的docker、Kubernetes源代码都采用go编写;云计算开发者学习go成为必然:)
go基本语法
- go作为一门脚本语言,其代码的可读性还是很强的,上手比较快,并且一旦编译生成可执行文件后,文件可以在任何机器运行;
- main 函数是每一个可执行程序所必须包含的,一般来说都是在启动后第一个执行的函数(如果有 init() 函数则会先执行init()函数);main 函数既没有参数,也没有返回类型;
- 使用 var 声明的变量的值会自动初始化为该类型的零值。
- Go 语言不存在隐式类型转换,因此所有的转换都必须显式说明,就像调用一个函数一样(类型在这里的作用可以看作是一种函数):
- Go 语言和 C、C++ 语言一样,都有指针的概念。 指针运算(所谓的指针算法,如:
pointer+2
,移动指针指向字符串的字节数或数组的某个位置)是不被允许的。Go 语言中的指针保证了内存安全。
- 函数的多返回值,可以监测到函数在执行过程中的错误:
value, err := pack1.Function1(param1)
if err != nil {
fmt.Printf("An error occured in pack1.Function1 with parameter %v", param1)
return err
}
// 未发生错误,继续执行;
- 函数体命名:
func 函数名(参数) 返回值类型 {
}
// eg:
func MultiPly3Nums(a int, b int, c int) int {
// var product int = a * b * c
// return product
return a * b * c
}
- 关键字 defer 的用法类似于面向对象编程语言 Java 的
finally
语句块,它一般用于释放某些已分配的资源。
func main() {
function1()
}
func function1() {
fmt.Printf("In function1 at the top\n")
defer function2()
fmt.Printf("In function1 at the bottom!\n")
}
func function2() {
fmt.Printf("function2: Deferred until the end of the calling function!")
}
// 输出如下:
In Function1 at the top
In Function1 at the bottom!
Function2: Deferred until the end of the calling function!
- 匿名函数:
// 表示参数列表的第一对括号必须紧挨着关键字 func,因为匿名函数没有名称。花括号 {} 涵盖着函数体,最后的一对括号表示对该匿名函数的调用。
func() {
sum = 0.0
for i := 1; i <= 1e6; i++ {
sum += i
}
}()
// 可以在需要的时候实现一个 where() 闭包函数来打印函数执行的位置:
where := func() {
_, file, line, _ := runtime.Caller(1)
log.Printf("%s:%d", file, line)
}
where()
// some codewhere()
// some more code
- 结构体定义的一般方式如下:
type identifier struct {
field1 type1
field2 type2
// ...
}
// 结构体赋值语句的惯用方法是:t := new(T),变量 t 是一个指向 T的指针,此时结构体字段的值是它们所属类型的零值:
type struct1 struct {
i1 int
f1 float32
str string
}
ms := new(struct1)
ms.i1 = 10
ms.f1 = 15.5
- 数组与切片
// 声明一个数组的格式是:
var arr1 [5]int
// 切片的初始化格式是:
var slice1 []type = arr1[start:end]
协程与管道
协程:
- 一个进程可以细化成多个线程
- 使用多线程可能会使得应用难以准确,内存中的数据是共享的,会被多线程以无法预知的方式进行操作,这就是竞态,因此go语言不提倡使用共享内存,使用共享内存在多线程情况下是危险的。避免危险的措施是同步(sync)不同的线程,对共享的数据进行加锁处理,这样在同一时刻上只有一个线程能够对数据进行变更。这样会带来更高的复杂度、容易使得代码出错以及更低的性能。
- 协程通过使用关键字
go
执行一个函数或方法来实现,这样会在当前的计算过程中开启一个同时执行的函数,在相同的地址空间中并对该函数分配了独立的栈,开发者不需要管理分配给协程的栈的大小,协程函数在运行完之后,会静默退出,函数不会返回任何值;
通道
- 协程之间可以使用共享变量来进行通信,但是效率低下,使用
channel
(管道)进行通信,可以避免共享内存导致的问题,同样也可以使得在同一时间只有一个协程可以访问数据;
- 通道服务于通信的两个目的:值的交换、同步,保证两个计算协程任何时候都是可知状态:
// string类型的通道的创建:
// 方式1:
var ch1 chan string
ch1 = make(chan string)
// 方式2:
ch1 := make(chan string)
- 对通道操作的操作符:
- 数据流向通道:
ch<-int1
,使用ch通道发送int1变量
- 数据冲通道流出:
int2=<-ch
,变量int2从ch通道中接收数据
- 就是生产者与接收者的模型
槽点
- go没有用于包管理的开源社区,开发者写好的轮子难以共享给他人用
- 生成的二进制可执行文件较大
- 当前,go代码阅读的官方IDE(JetBrains GoLand)每个月还需要更新一次:(
参考
Unknwon/the-way-to-go_ZH_CN
并发、并行和协程