mirror of
https://github.com/chai2010/go2-book.git
synced 2025-06-04 08:08:25 +00:00
zz
This commit is contained in:
parent
af8f033b45
commit
f13f21d387
@ -1,4 +1,9 @@
|
||||
# 目录
|
||||
|
||||
* [第1章 语法糖变迁](ch1/readme.md)
|
||||
* [1.1 Go1的语法变迁](ch1/ch1-1.md)
|
||||
* [第1章 语法变迁](ch1/readme.md)
|
||||
* [1.1 Go1的诺言](ch1/ch1-1.md)
|
||||
* [1.2 Go1到Go1.10](ch1/ch1-2.md)
|
||||
* [1.3 Go1.10过渡到Go2](ch1/ch1-3.md)
|
||||
* [1.4 Go2诞生](ch1/ch1-4.md)
|
||||
* [第2章 模块化](ch2/readme.md)
|
||||
* [第3章 错误处理](ch3/readme.md)
|
||||
|
88
ch1/ch1-1.md
88
ch1/ch1-1.md
@ -1,88 +1,8 @@
|
||||
## 1.1 Go1的语法变迁
|
||||
# 1.1 Go1的诺言
|
||||
|
||||
Go1的语法变迁主要从Go第一个正式版本开始,到Go1.10版本截止。最大的变化其实是在Go1发布时就已经完成了,而Go1到Go1.10期间仅仅增加了极少数的变动。
|
||||
Go语言从2007年开始设计,2009年底正式开源,而第一个正式的版本Go1则是在2012年上半年发布。Go1的语法变迁主要从Go第一个正式版本开始,Go1是Go语言官方对整个社区的承诺:Go1之后的版本将保证源代码层面兼容。
|
||||
|
||||
### 1.1.1 Go1的诺言
|
||||
从Go1的发布日志可以发现,Go1对语言和标准库做了严谨的梳理和完善,Go1的重大变化主要集中在语言和标准库部分。其中语言部分最大的变化是将原先的`os.Error`接口用内置的`error`接口类型替代、内置函数引入了`close`函数用户管道的关闭操作。此外,还对加强了`init`、`append`内置函数;增强了复合类型字面值的支持;针对Unicode字符增加了`rune`别名;改善了对map的遍历和删除元素操作;改进了影子返回值的报警提示;复制结构体时涵盖未导出的成员;明确了哪些类型可以进行相等性测试。同时对每个标准库的路径和功能进行详细的设计和完善。
|
||||
|
||||
Go语言从2007年开始设计,2009年底正式开源,而第一个正式的版本Go1则是在2012年上半年发布。Go1是Go语言官方对整个社区的承诺:Go1之后的版本将保证源代码层面兼容。从Go1的发布日志可以发现,Go1对语言和标准库做了严谨的梳理和完善,正是这次工作才奠定了Go1之后高速发展的十年。
|
||||
|
||||
Go1的重大变化主要集中在语言和标准库部分。经过多年的发展和普及,大家已经对Go语言目前的标准库非常熟悉了。我们这里主只回顾下Go1的语言变化(包含内置类型和函数)。
|
||||
|
||||
https://golang.org/doc/go1#language
|
||||
|
||||
|
||||
### 1.1.2 Go1到Go1.10
|
||||
|
||||
#### Go1.2
|
||||
|
||||
https://golang.org/doc/go1.2#language
|
||||
|
||||
#### Go1.4
|
||||
|
||||
https://golang.org/doc/go1.4#language
|
||||
|
||||
|
||||
#### Go1.5
|
||||
|
||||
https://golang.org/doc/go1.5#language
|
||||
|
||||
|
||||
#### Go1.8
|
||||
|
||||
https://golang.org/doc/go1.8#language
|
||||
|
||||
#### Go1.9
|
||||
|
||||
Go1.9终于引入了类型别名的特性。类型别名的特性如下:
|
||||
|
||||
```go
|
||||
type T1 = T2
|
||||
```
|
||||
|
||||
类型别名`T1`是通过`=`符号从`T2`定义,这里的`T1`和`T2`是完全相同的类型。
|
||||
|
||||
Go语言的接口是一大亮点特性,接口是方法的集合,而方法正是依附于类型的函数。而类型别名的一个特殊的地方是,`T1`并不是一个新的类型,因此我们不能再为`T1`定义任何新的方法。
|
||||
|
||||
之所以引入类型别名,很大的原因是为了解决Go1.7将`context`扩展库移动到标准库带来的问题。因为标准库和扩展库中分别定义了`context.Context`类型,而不同包中的类型是不相容的。而gRPC等很多开源的库使用的是最开始以来的扩展库中的`context.Context`类型,结果导致其无法和Go1.7标准库中的`context.Context`类型兼容。这个问题最终通过类型别名解决了:扩展库中的`context.Context`类型是标准库中`context.Context`的别名类型,从而实现了和标准库的兼容。
|
||||
|
||||
类型别名虽然是为了解决特定问题而引入的补丁特性。但是从类型别名我们可以发现一些有趣的用法:
|
||||
|
||||
```go
|
||||
type ReaderA interface {
|
||||
Read(p []byte) (n int, err error)
|
||||
}
|
||||
type ReaderB = interface {
|
||||
Read(p []byte) (n int, err error)
|
||||
}
|
||||
```
|
||||
|
||||
上面定义的两个读接口都有同样的方法集合。而Go语言的接口是采用隐式的转义,因此可能有人会觉得这两种写法根本没有什么意义!
|
||||
|
||||
但是接口本身也是一种类型,如果我们基于`ReaderA`和`ReaderB`类型继续构造新的方法,就产生了差异:
|
||||
|
||||
```go
|
||||
type MakeReaderA interface {
|
||||
MakeReader() ReaderA
|
||||
}
|
||||
type MakeReaderB interface {
|
||||
MakeReader() ReaderB
|
||||
}
|
||||
```
|
||||
|
||||
虽然接口定义方法的名字相同,但是方法返回的是两种不同的类型,因此方法的签名是不同的,所以说上面的两个接口并不相同。
|
||||
|
||||
我们现在考虑通过类型别名的方式定义一个`ReaderC`接口,然后定义一个`MakeReaderC`接口:
|
||||
|
||||
```go
|
||||
type ReaderC = interface {
|
||||
Read(p []byte) (n int, err error)
|
||||
}
|
||||
type MakeReaderC interface {
|
||||
MakeReader() ReaderC
|
||||
}
|
||||
```
|
||||
|
||||
比较神奇的是`MakeReaderC`和`MakeReaderB`接口可能是等价的,因为它定义的方法名和签名都是相同的。MakeReader方法返回的都是一个匿名的`interface { Read(p []byte) (n int, err error) }`接口类型。而Go语言中,所有的结构相同的匿名类型其实是同一个类型。
|
||||
|
||||
如果通过类型别名从匿名接口构造接口,就可以避免新定义的不同接口类型对接口的方法签名造成影响。
|
||||
经过多年的发展和普及,大家已经对Go1语言和标准库已经耳熟能详,对变更的细节就不详细展开了。但正是这次梳理工作才奠定了Go1之后高速发展的十年。
|
||||
|
||||
|
101
ch1/ch1-2.md
101
ch1/ch1-2.md
@ -1,3 +1,100 @@
|
||||
## Go1到Go2过渡期的语法变迁
|
||||
# 1.2 Go1到Go1.10
|
||||
|
||||
因为Go1承诺,Go1后序的版本都保持了向前兼容的目标。不过在从Go1发展到Go1.10的过程中,语言依然是增加了一些新的特性。本节我们简单回顾Go1到Go1.10的变化。
|
||||
|
||||
## 1.2.1 Go1.2
|
||||
|
||||
Go1.2最大的语言变化是切片操作时,可以设置新切片的容量。这个需求在Go1之前就被提出了,但是因为Go1修改工作较大而延期到了Go1.2才被实现。
|
||||
|
||||
比如下面的代码:
|
||||
|
||||
```go
|
||||
var a = make([]int, 10)
|
||||
var b = a[i:j:k]
|
||||
```
|
||||
|
||||
其中`b`切片是从`a`切片的第`i`个元素开始到第`j`个元素前结束,`b`切片的容量为`k`(`k`指定的容量不能超出`a`切片的容量)。
|
||||
|
||||
为了配合切片语法的变更,`reflect`包也增加了相应的方法:
|
||||
|
||||
```
|
||||
func (v Value) SetCap(cap int)
|
||||
func (v Value) Slice3(low, high, max int) Value
|
||||
```
|
||||
|
||||
其中`Value.SetCap`只调整切片的容量,和`a[::cap]`写法效果等价。而`Value.Slice3`在进行切片操作的同时也指定新切片的容量,和`a[low:high:max]`写法效果等价。
|
||||
|
||||
通过限制子切片的容量,可以将不同子切片进行安全的分割,避免子切片无意越界操作其它切片空间。
|
||||
|
||||
## 1.2.2 Go1.4
|
||||
|
||||
https://golang.org/doc/go1.4#language
|
||||
|
||||
|
||||
## 1.2.3 Go1.5
|
||||
|
||||
https://golang.org/doc/go1.5#language
|
||||
|
||||
## 1.2.4 Go1.7
|
||||
|
||||
https://golang.org/doc/go1.7#context
|
||||
|
||||
## 1.2.5 Go1.8
|
||||
|
||||
https://golang.org/doc/go1.8#language
|
||||
|
||||
## 1.2.6 Go1.9
|
||||
|
||||
Go1.9终于引入了类型别名的特性。类型别名的特性如下:
|
||||
|
||||
```go
|
||||
type T1 = T2
|
||||
```
|
||||
|
||||
类型别名`T1`是通过`=`符号从`T2`定义,这里的`T1`和`T2`是完全相同的类型。
|
||||
|
||||
Go语言的接口是一大亮点特性,接口是方法的集合,而方法正是依附于类型的函数。而类型别名的一个特殊的地方是,`T1`并不是一个新的类型,因此我们不能再为`T1`定义任何新的方法。
|
||||
|
||||
之所以引入类型别名,很大的原因是为了解决Go1.7将`context`扩展库移动到标准库带来的问题。因为标准库和扩展库中分别定义了`context.Context`类型,而不同包中的类型是不相容的。而gRPC等很多开源的库使用的是最开始以来的扩展库中的`context.Context`类型,结果导致其无法和Go1.7标准库中的`context.Context`类型兼容。这个问题最终通过类型别名解决了:扩展库中的`context.Context`类型是标准库中`context.Context`的别名类型,从而实现了和标准库的兼容。
|
||||
|
||||
类型别名虽然是为了解决特定问题而引入的补丁特性。但是从类型别名我们可以发现一些有趣的用法:
|
||||
|
||||
```go
|
||||
type ReaderA interface {
|
||||
Read(p []byte) (n int, err error)
|
||||
}
|
||||
type ReaderB = interface {
|
||||
Read(p []byte) (n int, err error)
|
||||
}
|
||||
```
|
||||
|
||||
上面定义的两个读接口都有同样的方法集合。而Go语言的接口是采用隐式的转义,因此可能有人会觉得这两种写法根本没有什么意义!
|
||||
|
||||
但是接口本身也是一种类型,如果我们基于`ReaderA`和`ReaderB`类型继续构造新的方法,就产生了差异:
|
||||
|
||||
```go
|
||||
type MakeReaderA interface {
|
||||
MakeReader() ReaderA
|
||||
}
|
||||
type MakeReaderB interface {
|
||||
MakeReader() ReaderB
|
||||
}
|
||||
```
|
||||
|
||||
虽然接口定义方法的名字相同,但是方法返回的是两种不同的类型,因此方法的签名是不同的,所以说上面的两个接口并不相同。
|
||||
|
||||
我们现在考虑通过类型别名的方式定义一个`ReaderC`接口,然后定义一个`MakeReaderC`接口:
|
||||
|
||||
```go
|
||||
type ReaderC = interface {
|
||||
Read(p []byte) (n int, err error)
|
||||
}
|
||||
type MakeReaderC interface {
|
||||
MakeReader() ReaderC
|
||||
}
|
||||
```
|
||||
|
||||
比较神奇的是`MakeReaderC`和`MakeReaderB`接口可能是等价的,因为它定义的方法名和签名都是相同的。MakeReader方法返回的都是一个匿名的`interface { Read(p []byte) (n int, err error) }`接口类型。而Go语言中,所有的结构相同的匿名类型其实是同一个类型。
|
||||
|
||||
如果通过类型别名从匿名接口构造接口,就可以避免新定义的不同接口类型对接口的方法签名造成影响。
|
||||
|
||||
TODO
|
||||
|
5
ch1/ch1-3.md
Normal file
5
ch1/ch1-3.md
Normal file
@ -0,0 +1,5 @@
|
||||
# 1.3 Go1.10过渡到Go2
|
||||
|
||||
<!--
|
||||
删除二进制包
|
||||
-->
|
1
ch1/ch1-4.md
Normal file
1
ch1/ch1-4.md
Normal file
@ -0,0 +1 @@
|
||||
# 1.4 Go2诞生
|
@ -1,4 +1,4 @@
|
||||
# 第1章 语法糖变迁
|
||||
# 第1章 语法变迁
|
||||
|
||||
Go语言语法糖变化非常少,主要发生在Go1.10之前。Go1.10主要的开发工作在2017年下半年完成,在2018年初正式发布。Go1.10版可以说是Go1和Go2的分水岭,虽然语言本身没有大的变化,但是Go语言官方正式开始准备Go2的前期设计工作。在Go1.10以前,很多关于语言细节修改的建议绝大部分都被冻结了。但是在Go1.10以后,语言改进的工作又重新纳入日程。本章重点回顾Go1.0发布以来,语言发生了哪些细微的变化。
|
||||
Go语言语法变化非常少,主要发生在Go1.10之前。Go1.10主要的开发工作在2017年下半年完成,在2018年初正式发布。Go1.10版可以说是Go1和Go2的分水岭,虽然语言本身没有大的变化,但是Go语言官方正式开始准备Go2的前期设计工作。在Go1.10以前,很多关于语言细节修改的建议绝大部分都被冻结了。但是在Go1.10以后,语言改进的工作又重新纳入日程。本章重点回顾Go1.0发布以来,语言发生了哪些细微的变化。
|
||||
|
||||
|
1
ch2/readme.md
Normal file
1
ch2/readme.md
Normal file
@ -0,0 +1 @@
|
||||
# 第2章 模块化
|
1
ch3/readme.md
Normal file
1
ch3/readme.md
Normal file
@ -0,0 +1 @@
|
||||
# 第3章 错误处理
|
Loading…
x
Reference in New Issue
Block a user