diff --git a/SUMMARY.md b/SUMMARY.md index 2e77308..f61a8f7 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -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) diff --git a/ch1/ch1-1.md b/ch1/ch1-1.md index 4182bc8..25bcbb9 100644 --- a/ch1/ch1-1.md +++ b/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之后高速发展的十年。 diff --git a/ch1/ch1-2.md b/ch1/ch1-2.md index 8e56dba..0e9e9ca 100644 --- a/ch1/ch1-2.md +++ b/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 diff --git a/ch1/ch1-3.md b/ch1/ch1-3.md new file mode 100644 index 0000000..31d31f7 --- /dev/null +++ b/ch1/ch1-3.md @@ -0,0 +1,5 @@ +# 1.3 Go1.10过渡到Go2 + + diff --git a/ch1/ch1-4.md b/ch1/ch1-4.md new file mode 100644 index 0000000..a46c31b --- /dev/null +++ b/ch1/ch1-4.md @@ -0,0 +1 @@ +# 1.4 Go2诞生 diff --git a/ch1/readme.md b/ch1/readme.md index 72eb3cd..18eeb01 100644 --- a/ch1/readme.md +++ b/ch1/readme.md @@ -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发布以来,语言发生了哪些细微的变化。 diff --git a/ch2/readme.md b/ch2/readme.md new file mode 100644 index 0000000..a162f32 --- /dev/null +++ b/ch2/readme.md @@ -0,0 +1 @@ +# 第2章 模块化 diff --git a/ch3/readme.md b/ch3/readme.md new file mode 100644 index 0000000..5f2aa9d --- /dev/null +++ b/ch3/readme.md @@ -0,0 +1 @@ +# 第3章 错误处理