fix encoding

This commit is contained in:
Unknown
2015-09-08 06:11:37 -04:00
parent 6486c61517
commit d977e88e8a
10 changed files with 218 additions and 218 deletions

View File

@@ -1,9 +1,9 @@
# 11 <EFBFBD>ӿڣ<EFBFBD>Interfaces<EFBFBD><EFBFBD><EFBFBD><EFBFBD>reflection<EFBFBD><EFBFBD> # 11 接口(Interfaces)与反射(reflection
<EFBFBD><EFBFBD><EFBFBD>½<EFBFBD><EFBFBD><EFBFBD> Go <20><><EFBFBD><EFBFBD><EFBFBD>нӿںͷ<DABA><CDB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݡ<EFBFBD> 本章介绍 Go 语言中接口和反射的相关内容。
## <EFBFBD><EFBFBD><EFBFBD><EFBFBD> ## 链接
- [Ŀ¼](directory.md) - [目录](directory.md)
- <EFBFBD><EFBFBD>һ<EFBFBD>ڣ<EFBFBD>[<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>պ<EFBFBD>SetFinalizer](10.8.md) - 上一节:[垃圾回收和SetFinalizer](10.8.md)
- <EFBFBD><EFBFBD>һ<EFBFBD>ڣ<EFBFBD>[<EFBFBD>ӿ<EFBFBD><EFBFBD><EFBFBD>ʲô](11.1.md) - 下一节:[接口是什么](11.1.md)

View File

@@ -1,12 +1,12 @@
# 11.1 <EFBFBD>ӿ<EFBFBD><EFBFBD><EFBFBD>ʲô # 11.1 接口是什么
Go <EFBFBD><EFBFBD><EFBFBD>Բ<EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD> *<2A><><EFBFBD><EFBFBD>ͳ<EFBFBD><CDB3>* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԣ<EFBFBD><D4A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>û<EFBFBD><C3BB><EFBFBD><EFBFBD><EFBFBD>ͼ̳еĸ<D0B5><C4B8> Go 语言不是一种 *“传统”* 的面向对象编程语言:它里面没有类和继承的概念。
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> Go <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>зdz<D0B7><C7B3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> **<EFBFBD>ӿ<EFBFBD>** <20><><EFBFBD>ͨ<EEA3AC><CDA8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD>ֺܶ<D6BA><DCB6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԡ<EFBFBD><D4A1>ӿ<EFBFBD><D3BF><EFBFBD><E1B9A9>һ<EFBFBD>ַ<EFBFBD>ʽ<EFBFBD><CABD> **˵<EFBFBD><EFBFBD>** <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˭<EFBFBD>ܸ㶨<DCB8><E3B6A8><EFBFBD><EFBFBD><EFBFBD>£<EFBFBD><C2A3><EFBFBD><EFBFBD>Ϳ<EFBFBD><CDBF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 但是 Go 语言里有非常灵活的 **接口** 概念,通过它可以实现很多面向对象的特性。接口提供了一种方式来 **说明** 对象的行为:如果谁能搞定这件事,它就可以用在这儿。
<EFBFBD>ӿڶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Щ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD>֣<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>û<EFBFBD>б<EFBFBD>ʵ<EFBFBD>֣<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>dz<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD><EFBFBD><EFBFBD>Ҳ<EFBFBD><EFBFBD><EFBFBD>ܰ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 接口定义了一组方法(方法集),但是这些方法不包含(实现)代码:它们没有被实现(它们是抽象的)。接口里也不能包含变量。
ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¸<EFBFBD>ʽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӿڣ<EFBFBD> 通过如下格式定义接口:
```go ```go
type Namer interface { type Namer interface {
@@ -16,35 +16,35 @@ type Namer interface {
} }
``` ```
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Namer` <EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD> **<EFBFBD>ӿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>**<2A><> 上面的 `Namer` 是一个 **接口类型**
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Լ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģ<EFBFBD><EFBFBD>ӿڵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `[e]r` <20><>׺<EFBFBD><D7BA><EFBFBD>ɣ<EFBFBD><C9A3><EFBFBD><EFBFBD><EFBFBD> `Printer`<EFBFBD><EFBFBD>`Reader`<EFBFBD><EFBFBD>`Writer`<EFBFBD><EFBFBD>`Logger`<EFBFBD><EFBFBD>`Converter`<EFBFBD>ȵȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һЩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>õķ<EFBFBD>ʽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>׺`er`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>`Recoverable`<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD>ӿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>`able`<EFBFBD><EFBFBD>β<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `I` <20><>ͷ<EFBFBD><CDB7><EFBFBD><EFBFBD> `.NET` <EFBFBD><EFBFBD> `Java` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (按照约定,只包含一个方法的)接口的名字由方法名加 `[e]r` 后缀组成,例如 `Printer``Reader``Writer``Logger``Converter`等等。还有一些不常用的方式(当后缀`er`不合适时),比如`Recoverable`,此时接口名以`able`结尾,或者以 `I` 开头(像 `.NET` `Java` 中那样)。
Go <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>еĽӿڶ<EFBFBD><EFBFBD>ܼ<EFBFBD><EFBFBD>̣<EFBFBD>ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>0<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>3<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Go 语言中的接口都很简短通常它们会包含0个、最多3个方法。
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԣ<EFBFBD><EFBFBD><EFBFBD> Go <20><><EFBFBD><EFBFBD><EFBFBD>нӿڿ<D3BF><DABF><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5>һ<EFBFBD><D2BB><EFBFBD>ӿ<EFBFBD><D3BF><EFBFBD><EFBFBD>͵ı<CDB5><C4B1><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB> **<EFBFBD>ӿ<EFBFBD>ֵ** <20><>`var ai Namer`<EFBFBD><EFBFBD>`ai`<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֣<EFBFBD>multiword<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݽṹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><EFBFBD> `nil`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD>Ȼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȫ<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>¡<EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD>ֵ<EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD>ǷǷ<EFBFBD><EFBFBD>ģ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Dz<EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҳû<EFBFBD>У<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>´<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 不像大多数面向对象编程语言,在 Go 语言中接口可以有值,一个接口类型的变量或一个 **接口值** `var ai Namer``ai`是一个多字multiword数据结构它的值是 `nil`。它本质上是一个指针,虽然不完全是一回事。指向接口值的指针是非法的,它们不仅一点用也没有,还会导致代码错误。
![](images/11.1_fig11.1.jpg?raw=true) ![](images/11.1_fig11.1.jpg?raw=true)
<EFBFBD>˴<EFBFBD><EFBFBD>ķ<EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ġ<EFBFBD> 此处的方法指针表是通过运行时反射能力构建的。
<EFBFBD><EFBFBD><EFBFBD>ͣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>壩ʵ<EFBFBD>ֽӿڷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>еķ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ÿһ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><EFBFBD>˵<EFBFBD><EFBFBD><EFBFBD>˴˷<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڸ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>͵ģ<EFBFBD>**<2A><>ʵ<EFBFBD>ֽӿ<D6BD>**<2A><>ͬʱ<CDAC><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҳ<EFBFBD><D2B2><EFBFBD><EFBFBD><EFBFBD>˸<EFBFBD><CBB8><EFBFBD><EFBFBD>͵Ľӿڡ<D3BF>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD> `Namer` <20>ӿ<EFBFBD><D3BF><EFBFBD><EFBFBD>͵ı<CDB5><C4B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ը<EFBFBD>ֵ<EFBFBD><D6B5> `ai` <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>е<EFBFBD>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD>ʵ<EFBFBD>ֵĽӿڷ<D3BF><DAB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȼ<EFBFBD><C8BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD>ͣ<EFBFBD>Ҳʵ<D2B2><CAB5><EFBFBD>˸ýӿڣ<D3BF><DAA3>ı<EFBFBD><C4B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5>`ai`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ߣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ע<EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD>ͷ<EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD>֣<EFBFBD>Ҳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>֮<EFBFBD>ı 类型(比如结构体)实现接口方法集中的方法,每一个方法的实现说明了此方法是如何作用于该类型的:**即实现接口**,同时方法集也构成了该类型的接口。实现了 `Namer` 接口类型的变量可以赋值给 `ai` (接收者值),此时方法表中的指针会指向被实现的接口方法。当然如果另一个类型(也实现了该接口)的变量被赋值给`ai`,这二者(译者注:指针和方法实现)也会随之改变。
**<EFBFBD><EFBFBD><EFBFBD>Ͳ<EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><EFBFBD>ʽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ij<EFBFBD><EFBFBD><EFBFBD>ӿڣ<EFBFBD><EFBFBD>ӿڱ<EFBFBD><EFBFBD><EFBFBD>ʽ<EFBFBD><EFBFBD>ʵ<EFBFBD>֡<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϳ<EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><EFBFBD>ͬһ<EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD>**<2A><> **类型不需要显式声明它实现了某个接口:接口被隐式地实现。多个类型可以实现同一个接口**
**ʵ<EFBFBD><EFBFBD>ij<EFBFBD><EFBFBD><EFBFBD>ӿڵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD>ֽӿڷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ķ<EFBFBD><EFBFBD><EFBFBD>**<EFBFBD><EFBFBD> **实现某个接口的类型(除了实现接口方法外)可以有其他的方法**
**һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϳ<EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD>**<EFBFBD><EFBFBD> **一个类型可以实现多个接口**
**<EFBFBD>ӿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϳ<EFBFBD><EFBFBD>԰<EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD>ʵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ã<EFBFBD> <20><>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><CAB5><EFBFBD>˴˽ӿڣ<D3BF><DAA3>ӿ<EFBFBD><D3BF>Ƕ<EFBFBD>̬<EFBFBD><CCAC><EFBFBD>ͣ<EFBFBD>**<2A><> **接口类型可以包含一个实例的引用, 该实例的类型实现了此接口(接口是动态类型)**
<EFBFBD><EFBFBD>ʹ<EFBFBD>ӿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֮<EFBFBD><EFBFBD><EFBFBD>Ŷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ߴ<EFBFBD><EFBFBD>ڲ<EFBFBD>ͬ<EFBFBD>İ<EFBFBD><EFBFBD>У<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>룺ֻҪ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><EFBFBD><EFBFBD>˽ӿ<EFBFBD><EFBFBD>еķ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><EFBFBD><EFBFBD>˴˽ӿڡ<EFBFBD> 即使接口在类型之后才定义,二者处于不同的包中,被单独编译:只要类型实现了接口中的方法,它就实现了此接口。
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Щ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD>ýӿھ<EFBFBD><EFBFBD>кܴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԡ<EFBFBD> 所有这些特性使得接口具有很大的灵活性。
<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӣ<EFBFBD> 第一个例子:
ʾ<EFBFBD><EFBFBD> 11.1 interfaces.go<EFBFBD><EFBFBD> 示例 11.1 interfaces.go
```go ```go
package main package main
@@ -77,30 +77,30 @@ func main() {
} }
``` ```
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 输出:
The square has area: 25.000000 The square has area: 25.000000
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ij<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Square` <EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD> `Shaper`<EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Area()`<EFBFBD><EFBFBD> 上面的程序定义了一个结构体 `Square` 和一个接口 `Shaper`,接口有一个方法 `Area()`
<EFBFBD><EFBFBD> `main()` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD> `Square` <20><>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߶<EFBFBD><DFB6><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Square`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Area()`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ε<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Square` ʵ<EFBFBD><EFBFBD><EFBFBD>˽ӿ<EFBFBD> `Shaper` <EFBFBD><EFBFBD> `main()` 方法中创建了一个 `Square` 的实例。在主程序外边定义了一个接收者类型是 `Square`方法的 `Area()`,用来计算正方形的面积:结构体 `Square` 实现了接口 `Shaper`
<EFBFBD><EFBFBD><EFBFBD>Կ<EFBFBD><EFBFBD>Խ<EFBFBD>һ<EFBFBD><EFBFBD> `Square` <EFBFBD><EFBFBD><EFBFBD>͵ı<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>͵ı<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>`areaIntf = sq1` <EFBFBD><EFBFBD> 所以可以将一个 `Square` 类型的变量赋值给一个接口类型的变量:`areaIntf = sq1`
<EFBFBD><EFBFBD><EFBFBD>ڽӿڱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD> `Square` <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ã<EFBFBD>ͨ<EFBFBD><CDA8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ե<EFBFBD><D4B5><EFBFBD> `Square` <EFBFBD>ϵķ<EFBFBD><EFBFBD><EFBFBD> `Area()`<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȻҲ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Square` <20><>ʵ<EFBFBD><CAB5><EFBFBD>ϵ<EFBFBD><CFB5>ô˷<C3B4><CBB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڽӿ<DABD>ʵ<EFBFBD><CAB5><EFBFBD>ϵ<EFBFBD><CFB5>ô˷<C3B4><CBB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˷ܣ<CBB7><DCA3><EFBFBD>ʹ<EFBFBD>˷<EFBFBD><CBB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>ԡ<EFBFBD><D4A1>ӿڱ<D3BF><DAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˽<EFBFBD><CBBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD>Ӧ<EFBFBD><D3A6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD> 现在接口变量包含一个指向 `Square` 变量的引用,通过它可以调用 `Square` 上的方法 `Area()`。当然也可以直接在 `Square` 的实例上调用此方法,但是在接口实例上调用此方法更令人兴奋,它使此方法更具有一般性。接口变量里包含了接收者实例的值和指向对应方法表的指针。
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> **<EFBFBD><EFBFBD>̬** <20><> Go <20><EFBFBD><E6B1BE><EFBFBD><EFBFBD>̬<EFBFBD><CCAC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA>֪<EFBFBD>ĸ<EFBFBD><C4B8><EFBFBD><EEA3BA><EFBFBD>ݵ<EFBFBD>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѡ<EFBFBD><D1A1><EFBFBD><EFBFBD>ȷ<EFBFBD>ķ<EFBFBD><C4B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˵<EFBFBD><CBB5>ͬһ<CDAC><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڲ<EFBFBD>ͬ<EFBFBD><CDAC>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD><EFBFBD>ƺ<EFBFBD><C6BA><EFBFBD><EFBFBD>ֳ<EFBFBD><D6B3><EFBFBD>ͬ<EFBFBD><CDAC><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA> 这是 **多态** 的 Go 版本,多态是面向对象编程中一个广为人知的概念:根据当前的类型选择正确的方法,或者说:同一种类型在不同的实例上似乎表现出不同的行为。
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Square` û<EFBFBD><EFBFBD>ʵ<EFBFBD><EFBFBD> `Area()` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣ<EFBFBD><EFBFBD> 如果 `Square` 没有实现 `Area()` 方法,编译器将会给出清晰的错误信息:
cannot use sq1 (type *Square) as type Shaper in assignment: cannot use sq1 (type *Square) as type Shaper in assignment:
*Square does not implement Shaper (missing Area method) *Square does not implement Shaper (missing Area method)
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Shaper` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Perimeter()`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>`Square` û<EFBFBD><EFBFBD>ʵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹû<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Square` ʵ<><CAB5><EFBFBD>ϵ<EFBFBD><CFB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҳ<EFBFBD><D2B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͬ<EFBFBD><CDAC><EFBFBD>Ĵ<EFBFBD><C4B4><EFBFBD><EFBFBD><EFBFBD> 如果 `Shaper` 有另外一个方法 `Perimeter()`,但是`Square` 没有实现它,即使没有人在 `Square` 实例上调用这个方法,编译器也会给出上面同样的错误。
<EFBFBD><EFBFBD>չһ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Rectangle` Ҳʵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Shaper` <EFBFBD>ӿڡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŵ<EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD> `Shaper` <20><><EFBFBD>͵<EFBFBD><CDB5><EFBFBD><EFBFBD><EFBFBD><E9A3AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ÿһ<C3BF><D2BB>Ԫ<EFBFBD>ز<EFBFBD><D8B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Area()` <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ<EFBFBD><D4B4><EFBFBD>չʾ<D5B9><CABE>̬<EFBFBD><CCAC>Ϊ<EFBFBD><CEAA> 扩展一下上面的例子,类型 `Rectangle` 也实现了 `Shaper` 接口。接着创建一个 `Shaper` 类型的数组,迭代它的每一个元素并在上面调用 `Area()` 方法,以此来展示多态行为:
ʾ<EFBFBD><EFBFBD> 11.2 interfaces_poly.go<EFBFBD><EFBFBD> 示例 11.2 interfaces_poly.go
```go ```go
package main package main
@@ -142,7 +142,7 @@ func main() {
} }
``` ```
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 输出:
Looping through shapes for area ... Looping through shapes for area ...
Shape details: {5 3} Shape details: {5 3}
@@ -150,13 +150,13 @@ func main() {
Shape details: &{5} Shape details: &{5}
Area of this shape is: 25 Area of this shape is: 25
<EFBFBD>ڵ<EFBFBD><EFBFBD><EFBFBD> `shapes[n].Area()) ` <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>ֻ֪<EFBFBD><EFBFBD> `shapes[n]` <EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD> `Shaper` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҡ<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD> `Square` <EFBFBD><EFBFBD> `Rectangle` <EFBFBD><EFBFBD><EFBFBD>󣬲<EFBFBD><EFBFBD>ұ<EFBFBD><EFBFBD>ֳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӧ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD> 在调用 `shapes[n].Area()) ` 这个时,只知道 `shapes[n]` 是一个 `Shaper` 对象,最后它摇身一变成为了一个 `Square` `Rectangle` 对象,并且表现出了相对应的行为。
Ҳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڿ<EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>β<EFBFBD><EFBFBD><EFBFBD> **<EFBFBD><EFBFBD><EFBFBD>ɾ<EFBFBD>**<2A><>**<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>** <20><> **<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>չ<EFBFBD><EFBFBD>** <20>Ĵ<EFBFBD><C4B4><EFBFBD><EBA1A3> 11.12.3 <20>н<EFBFBD><D0BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڿ<EFBFBD><DABF><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>µĽӿ<C4BD><D3BF>Ƕ<EFBFBD>ô<EFBFBD><C3B4><EFBFBD><EFBFBD><EFBFBD>ס<EFBFBD> 也许从现在开始你将看到通过接口如何产生 **更干净**、**更简单** 及 **更具有扩展性** 的代码。在 11.12.3 中将看到在开发中为类型添加新的接口是多么的容易。
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `stockPosition` <EFBFBD><EFBFBD> `car`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƕ<EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD> `getValue()` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǿ<EFBFBD><EFBFBD>Զ<EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д˷<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ľӿ<EFBFBD> `valuable`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŷ<EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD> `valuable`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ĺ<EFBFBD><EFBFBD><EFBFBD> `showValue()`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> `valuable` <EFBFBD>ӿڵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ͷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 下面是一个更具体的例子:有两个类型 `stockPosition` `car`,它们都有一个 `getValue()` 方法,我们可以定义一个具有此方法的接口 `valuable`。接着定义一个使用 `valuable`类型作为参数的函数 `showValue()`,所有实现了 `valuable` 接口的类型都可以用这个函数。
ʾ<EFBFBD><EFBFBD> 11.3 valuable.go<EFBFBD><EFBFBD> 示例 11.3 valuable.go
```go ```go
package main package main
@@ -202,14 +202,14 @@ func main() {
} }
``` ```
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 输出:
Value of the asset is 2308.800049 Value of the asset is 2308.800049
Value of the asset is 66500.000000 Value of the asset is 66500.000000
**һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>׼<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>** **一个标准库的例子**
`io`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Reader`: `io`包里有一个接口类型 `Reader`:
```go ```go
type Reader interface { type Reader interface {
@@ -217,9 +217,9 @@ type Reader interface {
} }
``` ```
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `r`<EFBFBD><EFBFBD>` var r io.Reader` 定义变量 `r`` var r io.Reader`
<EFBFBD><EFBFBD>ô<EFBFBD>Ϳ<EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><EFBFBD><EFBFBD>µĴ<EFBFBD><EFBFBD> 那么就可以写如下的代码:
```go ```go
var r io.Reader var r io.Reader
@@ -230,27 +230,27 @@ type Reader interface {
r = bufio.NewReader(f) r = bufio.NewReader(f)
``` ```
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> `r` <EFBFBD>ұߵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ͷ<EFBFBD>ʵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Read()` <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͬ<EFBFBD>ķ<EFBFBD><C4B7><EFBFBD>ǩ<EFBFBD><C7A9><EFBFBD><EFBFBD>`r` <20>ľ<EFBFBD>̬<EFBFBD><CCAC><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `io.Reader`<EFBFBD><EFBFBD> 上面 `r` 右边的类型都实现了 `Read()` 方法,并且有相同的方法签名,`r` 的静态类型是 `io.Reader`
**<EFBFBD><EFBFBD>ע** **备注**
<EFBFBD>е<EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>΢<EFBFBD><EFBFBD>ͬ<EFBFBD>ķ<EFBFBD>ʽ<EFBFBD><EFBFBD>ʹ<EFBFBD>ýӿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʣ<EFBFBD><EFBFBD><EFBFBD>ij<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͵ĽǶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ľӿ<EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>е<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>û<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʽ<EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD>Щ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>ӿڶ<EFBFBD><EFBFBD>ѡ<EFBFBD> 有的时候,也会以一种稍微不同的方式来使用接口这个词:从某个类型的角度来看,它的接口指的是:它的所有导出方法,只不过没有显式地为这些导出方法额外定一个接口而已。
**<EFBFBD><EFBFBD>ϰ 11.1** simple_interface.go<EFBFBD><EFBFBD> **练习 11.1** simple_interface.go
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD> `Simpler`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD> `Get()` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD> `Set()`<EFBFBD><EFBFBD>`Get()`<EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><EFBFBD>`Set()` <20><>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD>Ͳ<EFBFBD><CDB2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><E1B9B9><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Simple` ʵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӿڡ<EFBFBD> 定义一个接口 `Simpler`,它有一个 `Get()` 方法和一个 `Set()``Get()`返回一个整型值,`Set()` 有一个整型参数。创建一个结构体类型 `Simple` 实现这个接口。
<EFBFBD><EFBFBD><EFBFBD>Ŷ<EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD> `Simpler` <20><><EFBFBD>͵IJ<CDB5><C4B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ò<EFBFBD><C3B2><EFBFBD><EFBFBD><EFBFBD> `Get()` <EFBFBD><EFBFBD> `Set()` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `main` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȷ<EFBFBD><EFBFBD><EFBFBD>С<EFBFBD> 接着定一个函数,它有一个 `Simpler` 类型的参数,调用参数的 `Get()` `Set()` 方法。在 `main` 函数里调用这个函数,看看它是否可以正确运行。
**<EFBFBD><EFBFBD>ϰ 11.2** interfaces_poly2.go<EFBFBD><EFBFBD> **练习 11.2** interfaces_poly2.go
a) <EFBFBD><EFBFBD>չ interfaces_poly.go <EFBFBD>е<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD> `Circle` <EFBFBD><EFBFBD><EFBFBD><EFBFBD> a) 扩展 interfaces_poly.go 中的例子,添加一个 `Circle` 类型
b) ʹ<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Shape`<EFBFBD><EFBFBD>û<EFBFBD><EFBFBD><EFBFBD>ֶΣ<EFBFBD> ʵ<><CAB5>ͬ<EFBFBD><CDAC><EFBFBD>Ĺ<EFBFBD><C4B9>ܣ<EFBFBD><DCA3><EFBFBD>ʵ<EFBFBD>ֽӿ<D6BD> `Shaper`<EFBFBD><EFBFBD>Ȼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƕ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͡<EFBFBD><EFBFBD><EFBFBD>չ 10.6.5 <20>е<EFBFBD><D0B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˵<EFBFBD><CBB5><EFBFBD><EFBFBD>д<EFBFBD><D0B4> b) 使用一个抽象类型 `Shape`(没有字段) 实现同样的功能,它实现接口 `Shaper`,然后在其他类型里内嵌此类型。扩展 10.6.5 中的例子来说明覆写。
## <EFBFBD><EFBFBD><EFBFBD><EFBFBD> ## 链接
- [Ŀ¼](directory.md) - [目录](directory.md)
- <EFBFBD><EFBFBD>һ<EFBFBD>ڣ<EFBFBD>[<EFBFBD>ӿڣ<EFBFBD>Interfaces<EFBFBD><EFBFBD><EFBFBD><EFBFBD>reflection<EFBFBD><EFBFBD>](11.0.md) - 上一节:[接口(Interfaces)与反射(reflection](11.0.md)
- <EFBFBD><EFBFBD>һ<EFBFBD>ڣ<EFBFBD>[<EFBFBD>ӿ<EFBFBD>Ƕ<EFBFBD>׽ӿ<EFBFBD>](11.2.md) - 下一节:[接口嵌套接口](11.2.md)

View File

@@ -1,8 +1,8 @@
# 11.2 <EFBFBD>ӿ<EFBFBD>Ƕ<EFBFBD>׽ӿ<EFBFBD> # 11.2 接口嵌套接口
һ<EFBFBD><EFBFBD><EFBFBD>ӿڿ<EFBFBD><EFBFBD>԰<EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ľӿڣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֱ<EFBFBD>ӽ<EFBFBD><EFBFBD><EFBFBD>Щ<EFBFBD><EFBFBD>Ƕ<EFBFBD>ӿڵķ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>о<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> 一个接口可以包含一个或多个其他的接口,这相当于直接将这些内嵌接口的方法列举在外层接口中一样。
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD> `File` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `ReadWrite` <EFBFBD><EFBFBD> `Lock` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>з<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD> `Close()` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 比如接口 `File` 包含了 `ReadWrite` `Lock` 的所有方法,它还额外有一个 `Close()` 方法。
```go ```go
type ReadWrite interface { type ReadWrite interface {
@@ -22,8 +22,8 @@ type File interface {
} }
``` ```
## <EFBFBD><EFBFBD><EFBFBD><EFBFBD> ## 链接
- [Ŀ¼](directory.md) - [目录](directory.md)
- <EFBFBD><EFBFBD>һ<EFBFBD>ڣ<EFBFBD>[<EFBFBD>ӿ<EFBFBD><EFBFBD><EFBFBD>ʲô](11.1.md) - 上一节:[接口是什么](11.1.md)
- <EFBFBD><EFBFBD>һ<EFBFBD>ڣ<EFBFBD>[<EFBFBD><EFBFBD><EFBFBD>μ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD><EFBFBD><EFBFBD>ӿڱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ͷ<EFBFBD><EFBFBD><EFBFBD>](11.3.md) - 下一节:[如何检测和转换接口变量的类型:类型断言](11.3.md)

View File

@@ -1,14 +1,14 @@
# 11.3 <EFBFBD><EFBFBD><EFBFBD>Ͷ<EFBFBD><EFBFBD>ԣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>μ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD><EFBFBD><EFBFBD>ӿڱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> # 11.3 类型断言:如何检测和转换接口变量的类型
һ<EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>͵ı<EFBFBD><EFBFBD><EFBFBD> `varI` <20>п<EFBFBD><D0BF>԰<EFBFBD><D4B0><EFBFBD><EFBFBD>κ<EFBFBD><CEBA><EFBFBD><EFBFBD>͵<EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD>ַ<EFBFBD>ʽ<EFBFBD><CABD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> **<EFBFBD><EFBFBD>̬** <20><><EFBFBD>ͣ<EFBFBD><CDA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD>ڱ<EFBFBD><DAB1><EFBFBD><EFBFBD>д洢<D0B4><E6B4A2>ֵ<EFBFBD><D6B5>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD><EFBFBD>͡<EFBFBD><CDA1><EFBFBD>ִ<EFBFBD>й<EFBFBD><D0B9><EFBFBD><EFBFBD>ж<EFBFBD>̬<EFBFBD><CCAC><EFBFBD>Ϳ<EFBFBD><CDBF>ܻ<EFBFBD><DCBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͬ<EFBFBD><CDAC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǿ<EFBFBD><C7BF>Է<EFBFBD><D4B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӿڱ<D3BF><DAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͡<EFBFBD>ͨ<EFBFBD><CDA8><EFBFBD><EFBFBD><EFBFBD>ǿ<EFBFBD><C7BF><EFBFBD>ʹ<EFBFBD><CAB9> **<EFBFBD><EFBFBD><EFBFBD>Ͷ<EFBFBD><EFBFBD><EFBFBD>** <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ij<EFBFBD><C4B3>ʱ<EFBFBD><CAB1> `varI` <20>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `T` <EFBFBD><EFBFBD>ֵ<EFBFBD><EFBFBD> 一个接口类型的变量 `varI` 中可以包含任何类型的值,必须有一种方式来检测它的 **动态** 类型,即运行时在变量中存储的值的实际类型。在执行过程中动态类型可能会有所不同,但是它总是可以分配给接口变量本身的类型。通常我们可以使用 **类型断言** 来测试在某个时刻 `varI` 是否包含类型 `T` 的值:
```go ```go
v := varI.(T) // unchecked type assertion v := varI.(T) // unchecked type assertion
``` ```
**varI<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>ӿڱ<EFBFBD><EFBFBD><EFBFBD>**<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>`invalid type assertion: varI.(T) (non-interface type (type of varI) on left)` <EFBFBD><EFBFBD> **varI必须是一个接口变量**,否则编译器会报错:`invalid type assertion: varI.(T) (non-interface type (type of varI) on left)`
<EFBFBD><EFBFBD><EFBFBD>Ͷ<EFBFBD><EFBFBD>Կ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ч<EFBFBD>ģ<EFBFBD><EFBFBD><EFBFBD>Ȼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><EFBFBD><EFBFBD>Ч<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ԥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>еĿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD><EFBFBD><EFBFBD>ڳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱʧ<EFBFBD>ܻᵼ<EFBFBD>´<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȫ<EFBFBD>ķ<EFBFBD>ʽ<EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ͷ<EFBFBD><EFBFBD>ԣ<EFBFBD> 类型断言可能是无效的,虽然编译器会尽力检查转换是否有效,但是它不可能预见所有的可能性。如果转换在程序运行时失败会导致错误发生。更安全的方式是使用以下形式来进行类型断言:
```go ```go
if v, ok := varI.(T); ok { // checked type assertion if v, ok := varI.(T); ok { // checked type assertion
@@ -18,11 +18,11 @@ if v, ok := varI.(T); ok { // checked type assertion
// varI is not of type T // varI is not of type T
``` ```
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD><EFBFBD><EFBFBD>Ϸ<EFBFBD><EFBFBD><EFBFBD>`v` <EFBFBD><EFBFBD> `varI` ת<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `T`<EFBFBD><EFBFBD>ֵ<EFBFBD><EFBFBD>`ok` <EFBFBD><EFBFBD><EFBFBD><EFBFBD> `true`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `v` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `T` <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><EFBFBD>`ok` <EFBFBD><EFBFBD> `false`<EFBFBD><EFBFBD>Ҳû<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 如果转换合法,`v` `varI` 转换到类型 `T`的值,`ok` 会是 `true`;否则 `v` 是类型 `T` 的零值,`ok` `false`,也没有运行时错误发生。
**Ӧ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ķ<EFBFBD>ʽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ͷ<EFBFBD><EFBFBD><EFBFBD>**<EFBFBD><EFBFBD> **应该总是使用上面的方式来进行类型断言**
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>£<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǿ<EFBFBD><EFBFBD><EFBFBD>ֻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `if` <20>в<EFBFBD><D0B2><EFBFBD>һ<EFBFBD><D2BB> `ok` <20><>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD>ʱʹ<CAB1><CAB9><EFBFBD><EFBFBD><EFBFBD>µķ<C2B5><C4B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EEB7BD><EFBFBD>ģ<EFBFBD> 多数情况下,我们可能只是想在 `if` 中测试一下 `ok` 的值,此时使用以下的方法会是最方便的:
```go ```go
if _, ok := varI.(T); ok { if _, ok := varI.(T); ok {
@@ -30,9 +30,9 @@ if _, ok := varI.(T); ok {
} }
``` ```
TODO ??<EFBFBD><EFBFBD>In this form shadowing the variable varI by giving varI and v the same name is sometimes done. TODO ??In this form shadowing the variable varI by giving varI and v the same name is sometimes done.
ʾ<EFBFBD><EFBFBD> 11.4 type_interfaces.go 示例 11.4 type_interfaces.go
```go ```go
package main package main
@@ -80,19 +80,19 @@ func (ci *Circle) Area() float32 {
} }
``` ```
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 输出:
The type of areaIntf is: *main.Square The type of areaIntf is: *main.Square
areaIntf does not contain a variable of type Circle areaIntf does not contain a variable of type Circle
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Circle`<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҳʵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Shaper` <EFBFBD>ӿڡ<EFBFBD> `t, ok := areaIntf.(*Square); ok ` <EFBFBD><EFBFBD><EFBFBD><EFBFBD> `areaIntf` <EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 'Square' <20><><EFBFBD>͵ı<CDB5><C4B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȷ<EFBFBD><C8B7><EFBFBD>ģ<EFBFBD>Ȼ<EFBFBD><C8BB><EFBFBD><EFBFBD><EFBFBD>Dz<EFBFBD><C7B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB> 'Circle' <20><><EFBFBD>͵ı<CDB5><C4B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƿ񶨵ġ<F1B6A8B5> 程序行中定义了一个新类型 `Circle`,它也实现了 `Shaper` 接口。 `t, ok := areaIntf.(*Square); ok ` 测试 `areaIntf` 里是否一个包含 'Square' 类型的变量,结果是确定的;然后我们测试它是否包含一个 'Circle' 类型的变量,结果是否定的。
**<EFBFBD><EFBFBD>ע** **备注**
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `areaIntf.(*Square)` <EFBFBD>е<EFBFBD> `*` <EFBFBD>ţ<EFBFBD><EFBFBD><EFBFBD>±<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>`impossible type assertion: Square does not implement Shaper (Area method has pointer receiver)`<EFBFBD><EFBFBD> 如果忽略 `areaIntf.(*Square)` 中的 `*` 号,会导致编译错误:`impossible type assertion: Square does not implement Shaper (Area method has pointer receiver)`
## <EFBFBD><EFBFBD><EFBFBD><EFBFBD> ## 链接
- [Ŀ¼](directory.md) - [目录](directory.md)
- <EFBFBD><EFBFBD>һ<EFBFBD>ڣ<EFBFBD>[<EFBFBD>ӿ<EFBFBD>Ƕ<EFBFBD>׽ӿ<EFBFBD>](11.2.md) - 上一节:[接口嵌套接口](11.2.md)
- <EFBFBD><EFBFBD>һ<EFBFBD>ڣ<EFBFBD>[<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>жϣ<EFBFBD>type-switch](11.4.md) - 下一节:[类型判断:type-switch](11.4.md)

View File

@@ -1,6 +1,6 @@
# 11.4 <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>жϣ<EFBFBD>type-switch # 11.4 类型判断:type-switch
<EFBFBD>ӿڱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʽ<EFBFBD><EFBFBD> `swtich` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>**type-swtich** <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ʾ<><CABE> 11.4 <20>ĵڶ<C4B5><DAB6><EFBFBD><EFBFBD>֣<EFBFBD><D6A3><EFBFBD> 接口变量的类型也可以使用一种特殊形式的 `swtich` 来检测:**type-swtich** (下面是 示例 11.4 的第二部分):
```go ```go
switch t := areaIntf.(type) { switch t := areaIntf.(type) {
@@ -15,15 +15,15 @@
} }
``` ```
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 输出:
Type Square *main.Square with value &{5} Type Square *main.Square with value &{5}
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> `t` <EFBFBD>õ<EFBFBD><EFBFBD><EFBFBD> `areaIntf` <EFBFBD><EFBFBD>ֵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͣ<EFBFBD> <20><><EFBFBD><EFBFBD> `case` <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>оٵ<D0BE><D9B5><EFBFBD><EFBFBD>ͣ<EFBFBD>`nil` <20><><EFBFBD><EFBFBD><E2A3A9><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD>ֶ<EFBFBD>Ӧ<EFBFBD>Ľӿڣ<D3BF><DAA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>м<EFBFBD> `Shaper`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>û<EFBFBD><EFBFBD><EFBFBD><EFBFBD> `case` <20><><EFBFBD><EFBFBD><EFBFBD>оٵ<D0BE><D9B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>У<EFBFBD><D0A3>ͻ<EFBFBD>ִ<EFBFBD><D6B4>`default` <EFBFBD><EFBFBD><EFBFBD> 变量 `t` 得到了 `areaIntf` 的值和类型, 所有 `case` 语句中列举的类型(`nil` 除外)都必须实现对应的接口(在上例中即 `Shaper`),如果被检测类型没有在 `case` 语句列举的类型中,就会执行`default` 语句。
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `type-switch` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD>ͷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `type-switch` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `fallthrough` <EFBFBD><EFBFBD> 可以用 `type-switch` 进行运行时类型分析,但是在 `type-switch` 不允许有 `fallthrough`
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Dz<EFBFBD><EFBFBD>Ա<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ô<EFBFBD>Ϳ<EFBFBD><EFBFBD>Բ<EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><EFBFBD>ֵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 如果仅仅是测试变量的类型,不用它的值,那么就可以不需要赋值语句,比如:
```go ```go
switch areaIntf.(type) { switch areaIntf.(type) {
@@ -37,7 +37,7 @@
} }
``` ```
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD>Ƭ<EFBFBD><EFBFBD>չʾ<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>ɱ䳤<EFBFBD>Ȳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͵<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ԫ<EFBFBD>ص<EFBFBD>ʵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD>в<EFBFBD>ͬ<EFBFBD>Ķ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 下面的代码片段展示了一个类型分类函数,它有一个可变长度参数,可以是任意类型的数组,它会根据数组元素的实际类型执行不同的动作:
```go ```go
@@ -61,18 +61,18 @@ func classifier(items ...interface{}) {
} }
``` ```
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ô˷<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>`classifier(13, -14.3, "BELGIUM", complex(1, 2), nil, false)` <EFBFBD><EFBFBD> 可以这样调用此方法:`classifier(13, -14.3, "BELGIUM", complex(1, 2), nil, false)`
<EFBFBD>ڴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ⲿ<EFBFBD>ġ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>δ֪<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> JSON <EFBFBD><EFBFBD> XML <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ͳ<EFBFBD><EFBFBD>Ժ<EFBFBD>ת<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>dz<EFBFBD><EFBFBD><EFBFBD><EFBFBD>á<EFBFBD> 在处理来自于外部的、类型未知的数据时,比如解析诸如 JSON XML 编码的数据,类型测试和转换会非常有用。
<EFBFBD><EFBFBD> ʾ<><CABE>12.17(xml.go) <EFBFBD>н<EFBFBD><EFBFBD><EFBFBD> XML <20>ĵ<EFBFBD><C4B5>ǣ<EFBFBD><C7A3><EFBFBD><EFBFBD>Ǿͻ<C7BE><CDBB>õ<EFBFBD> `type-switch` <EFBFBD><EFBFBD> 在 示例12.17(xml.go) 中解析 XML 文档是,我们就会用到 `type-switch`
**<EFBFBD><EFBFBD>ϰ 11.4** simple_interface2.go<EFBFBD><EFBFBD> **练习 11.4** simple_interface2.go
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>ϰ11.1 <20>е<EFBFBD><D0B5><EFBFBD><EFBFBD>ݣ<EFBFBD><DDA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڶ<EFBFBD><DAB6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `RSimple`<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҳʵ<EFBFBD><EFBFBD><EFBFBD>˽ӿ<EFBFBD> `Simpler`<EFBFBD><EFBFBD>дһ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `fi`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Simple` <EFBFBD><EFBFBD> `RSimple` <EFBFBD><EFBFBD><EFBFBD>͵ı<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 接着 练习11.1 中的内容,创建第二个类型 `RSimple`,它也实现了接口 `Simpler`,写一个函数 `fi`,它可以区分 `Simple` `RSimple` 类型的变量。
## <EFBFBD><EFBFBD><EFBFBD><EFBFBD> ## 链接
- [Ŀ¼](directory.md) - [目录](directory.md)
- <EFBFBD><EFBFBD>һ<EFBFBD>ڣ<EFBFBD>[<EFBFBD><EFBFBD><EFBFBD>Ͷ<EFBFBD><EFBFBD>ԣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>μ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD><EFBFBD><EFBFBD>ӿڱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>](11.3.md) - 上一节:[类型断言:如何检测和转换接口变量的类型](11.3.md)
- <EFBFBD><EFBFBD>һ<EFBFBD>ڣ<EFBFBD>[<EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD>ֵ<EFBFBD>Ƿ<EFBFBD>ʵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ij<EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD>](11.5.md) - 下一节:[测试一个值是否实现了某个接口](11.5.md)

View File

@@ -1,6 +1,6 @@
# 11.5 <EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD>ֵ<EFBFBD>Ƿ<EFBFBD>ʵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ij<EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD> # 11.5 测试一个值是否实现了某个接口
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> 11.3 <EFBFBD><EFBFBD><EFBFBD>Ͷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>е<EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ٶ<EFBFBD> `v` <20><>һ<EFBFBD><D2BB>ֵ<EFBFBD><D6B5>Ȼ<EFBFBD><C8BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD> `Stringer` <20>ӿڣ<D3BF><DAA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 这是 11.3 类型断言中的一个特例:假定 `v` 是一个值,然后我们想测试它是否实现了 `Stringer` 接口,可以这样做:
```go ```go
type Stringer interface { type Stringer interface {
@@ -12,20 +12,20 @@ if sv, ok := v.(Stringer); ok {
} }
``` ```
`Print` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˼<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ<EFBFBD>ӡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ġ<EFBFBD> `Print` 函数就是如此检测类型是否可以打印自身的。
<EFBFBD>ӿ<EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Լ<EFBFBD><EFBFBD>ʵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͵<EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʲô<EFBFBD><EFBFBD><EFBFBD>ӿڳ<EFBFBD><EFBFBD>׽<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʲô<EFBFBD><EFBFBD><EFBFBD>Լ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͬ<EFBFBD>ӿڵı<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڲ<EFBFBD>ͬ<EFBFBD><EFBFBD>ʱ<EFBFBD>̱<EFBFBD><EFBFBD>ֳ<EFBFBD><EFBFBD><EFBFBD>ͬ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƕ<EFBFBD>̬<EFBFBD>ı<EFBFBD><EFBFBD>ʡ<EFBFBD> 接口是一种契约,实现类型必须满足它,它描述了类型的行为,规定类型可以做什么。接口彻底将类型能做什么,以及如何做分离开来,使得相同接口的变量在不同的时刻表现出不同的行为,这就是多态的本质。
<EFBFBD><EFBFBD>д<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǽӿڱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ĺ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ǹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>ԡ<EFBFBD> 编写参数是接口变量的函数,这使得它们更具有一般性。
**ʹ<EFBFBD>ýӿ<EFBFBD>ʹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԡ<EFBFBD>** **使用接口使代码更具有普适性。**
<EFBFBD><EFBFBD>׼<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Խӿڸ<EFBFBD><EFBFBD><EFBFBD>û<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>õİ<EFBFBD><EFBFBD>գ<EFBFBD><EFBFBD>Dz<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ι<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ġ<EFBFBD> 标准库里到处都使用了这个原则,如果对接口概念没有良好的把握,是不可能理解它是如何构建的。
<EFBFBD>ڽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>½<EFBFBD><EFBFBD>У<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϳ<EFBFBD><EFBFBD>Ը<EFBFBD><EFBFBD>õ<EFBFBD>Ӧ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> 在接下来的章节中,我们会讨论两个重要的例子,试着去深入理解它们,这样你就可以更好的应用上面的原则。
## <EFBFBD><EFBFBD><EFBFBD><EFBFBD> ## 链接
- [Ŀ¼](directory.md) - [目录](directory.md)
- <EFBFBD><EFBFBD>һ<EFBFBD>ڣ<EFBFBD>[<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>жϣ<EFBFBD>type-switch](11.4.md) - 上一节:[类型判断:type-switch](11.4.md)
- <EFBFBD><EFBFBD>һ<EFBFBD>ڣ<EFBFBD>[ʹ<EFBFBD>÷<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD>](11.6.md) - 下一节:[使用方法集与接口](11.6.md)

View File

@@ -1,8 +1,8 @@
# 11.6 ʹ<EFBFBD>÷<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD> # 11.6 使用方法集与接口
<EFBFBD><EFBFBD> 10.6.3 <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> methodset1.go <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϵķ<EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Dz<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD>ġ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>е<EFBFBD>ӣ<EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD>ǽӿڱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>д洢<EFBFBD>ľ<EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD>Dz<EFBFBD><EFBFBD><EFBFBD>Ѱַ<EFBFBD>ģ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>˵<EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD>ò<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>󡣿<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ij<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 10.6.3 及例子 methodset1.go 中我们看到,作用于变量上的方法实际上是不区分变量到底是指针还是值的。当碰到接口类型值时,这会变得有点复杂,原因是接口变量中存储的具体值是不可寻址的,幸运的是,如果使用不当编译器会给出错误。考虑下面的程序:
ʾ<EFBFBD><EFBFBD> 11.5 methodset2.go: 示例 11.5 methodset2.go:
```go ```go
package main package main
@@ -60,34 +60,34 @@ func main() {
} }
``` ```
**<EFBFBD><EFBFBD><EFBFBD><EFBFBD>** **讨论**
<EFBFBD><EFBFBD> `lst` <EFBFBD>ϵ<EFBFBD><EFBFBD><EFBFBD> `CountInto` ʱ<EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ `CountInto` <EFBFBD><EFBFBD>Ҫһ<EFBFBD><EFBFBD> `Appender`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ķ<EFBFBD><EFBFBD><EFBFBD> `Append` ֻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD>ϡ<EFBFBD> <20><> `lst` <EFBFBD>ϵ<EFBFBD><EFBFBD><EFBFBD> `LongEnough` <EFBFBD>ǿ<EFBFBD><EFBFBD>Ե<EFBFBD><EFBFBD><EFBFBD>Ϊ 'Len' <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD>ϡ<EFBFBD> `lst` 上调用 `CountInto` 时会导致一个编译器错误,因为 `CountInto` 需要一个 `Appender`,而它的方法 `Append` 只定义在指针上。 在 `lst` 上调用 `LongEnough` 是可以的因为 'Len' 定义在值上。
<EFBFBD><EFBFBD> `plst` <EFBFBD>ϵ<EFBFBD><EFBFBD><EFBFBD> `CountInto` <EFBFBD>ǿ<EFBFBD><EFBFBD>Եģ<EFBFBD><EFBFBD><EFBFBD>Ϊ `CountInto` <EFBFBD><EFBFBD>Ҫһ<EFBFBD><EFBFBD> `Appender`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ķ<EFBFBD><EFBFBD><EFBFBD> `Append` <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8><EFBFBD>ϡ<EFBFBD> <20><> `plst` <EFBFBD>ϵ<EFBFBD><EFBFBD><EFBFBD> `LongEnough` Ҳ<EFBFBD>ǿ<EFBFBD><EFBFBD>Եģ<EFBFBD><EFBFBD><EFBFBD>Ϊָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>á<EFBFBD> `plst` 上调用 `CountInto` 是可以的,因为 `CountInto` 需要一个 `Appender`,并且它的方法 `Append` 定义在指针上。 在 `plst` 上调用 `LongEnough` 也是可以的,因为指针会被自动解引用。
**<EFBFBD>ܽ<EFBFBD>** **总结**
<EFBFBD>ڽӿ<EFBFBD><EFBFBD>ϵ<EFBFBD><EFBFBD>÷<EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>кͷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>ͬ<EFBFBD>Ľ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǿ<EFBFBD><EFBFBD>ԴӾ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `P` ֱ<>ӿ<EFBFBD><D3BF>Ա<EFBFBD>ʶ<EFBFBD>ģ<EFBFBD> 在接口上调用方法时,必须有和方法定义时相同的接收者类型或者是可以从具体类型 `P` 直接可以辨识的:
- ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> - 指针方法可以通过指针调用
- ֵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD>ֵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> - 值方法可以通过值调用
- <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD>ķ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ã<EFBFBD><EFBFBD><EFBFBD>Ϊָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> - 接收者是值的方法可以通过指针调用,因为指针会首先被解引用
- <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD>ķ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD>ֵ<EFBFBD><EFBFBD><EFBFBD>ã<EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD>ڽӿ<EFBFBD><EFBFBD>е<EFBFBD>ֵû<EFBFBD>е<EFBFBD>ַ - 接收者是指针的方法不可以通过值调用,因为存储在接口中的值没有地址
<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD>ֵ<EFBFBD><EFBFBD>ֵ<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>ӿڸ<EFBFBD>ֵʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>п<EFBFBD><EFBFBD>ܵĽӿڷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD>ֵ<EFBFBD>ϱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ã<EFBFBD><EFBFBD><EFBFBD><EFBFBD>˲<EFBFBD><EFBFBD><EFBFBD>ȷ<EFBFBD>ĸ<EFBFBD>ֵ<EFBFBD>ڱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ھͻ<EFBFBD>ʧ<EFBFBD>ܡ<EFBFBD> 将一个值赋值给一个接口赋值时,编译器会确保所有可能的接口方法都可以在此值上被调用,因此不正确的赋值在编译期就会失败。
**<EFBFBD><EFBFBD>ע** **译注**
Go<EFBFBD><EFBFBD><EFBFBD>Թ淶<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˽ӿڷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD>ù<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Go语言规范定义了接口方法集的调用规则:
- <EFBFBD><EFBFBD><EFBFBD><EFBFBD> *T <20>Ŀɵ<C4BF><C9B5>÷<EFBFBD><C3B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ *T <EFBFBD><EFBFBD> T <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>з<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> - 类型 *T 的可调用方法集包含接受者为 *T T 的所有方法集
- <EFBFBD><EFBFBD><EFBFBD><EFBFBD> T <20>Ŀɵ<C4BF><C9B5>÷<EFBFBD><C3B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ T <20><><EFBFBD><EFBFBD><EFBFBD>з<EFBFBD><D0B7><EFBFBD> - 类型 T 的可调用方法集包含接受者为 T 的所有方法
- <EFBFBD><EFBFBD><EFBFBD><EFBFBD> T <20>Ŀɵ<C4BF><C9B5>÷<EFBFBD><C3B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ *T <20>ķ<EFBFBD><C4B7><EFBFBD> - 类型 T 的可调用方法集不包含接受者为 *T 的方法
## <EFBFBD><EFBFBD><EFBFBD><EFBFBD> ## 链接
- [Ŀ¼](directory.md) - [目录](directory.md)
- <EFBFBD><EFBFBD>һ<EFBFBD>ڣ<EFBFBD>[<EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD>ֵ<EFBFBD>Ƿ<EFBFBD>ʵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ij<EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD>](11.5.md) - 上一节:[测试一个值是否实现了某个接口](11.5.md)
- <EFBFBD><EFBFBD>һ<EFBFBD>ڣ<EFBFBD>[<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӣ<EFBFBD>ʹ<EFBFBD><EFBFBD>Sorter<EFBFBD>ӿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>](11.7.md) - 下一节:[第一个例子使用Sorter接口排序](11.7.md)

View File

@@ -1,9 +1,9 @@
# 11.7 <EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӣ<EFBFBD>ʹ<EFBFBD><EFBFBD>Sorter<EFBFBD>ӿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> # 11.7 第一个例子使用Sorter接口排序
һ<EFBFBD><EFBFBD><EFBFBD>ܺõ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ա<EFBFBD>׼<EFBFBD><EFBFBD><EFBFBD><EFBFBD> `sort` <20><><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD>ֻ<EFBFBD><D6BB>ַ<EFBFBD><D6B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֻ<EFBFBD><D6BB>Ҫʵ<D2AA><CAB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӳԪ<D3B3>ظ<EFBFBD><D8B8><EFBFBD><EFBFBD><EFBFBD> `Len()`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƚϵ<EFBFBD> `i` <EFBFBD><EFBFBD> `j` <EFBFBD><EFBFBD>Ԫ<EFBFBD>ص<EFBFBD> `Less(i, j)` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Լ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `i` <EFBFBD><EFBFBD> `j` <EFBFBD><EFBFBD>Ԫ<EFBFBD>ص<EFBFBD> `Swap(i, j)` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 一个很好的例子是来自标准库的 `sort` 包,要对一组数字或字符串排序,只需要实现三个方法:反映元素个数的 `Len()`方法、比较第 `i` `j` 个元素的 `Less(i, j)` 方法以及交换第 `i` `j` 个元素的 `Swap(i, j)` 方法。
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>㷨ֻ<EFBFBD><EFBFBD>ʹ<EFBFBD>õ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD><EFBFBD>κ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD>֣<EFBFBD><EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>ð<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>򣩣<EFBFBD> 排序函数的算法只会使用到这三个方法(可以使用任何排序算法来实现,此处我们使用冒泡排序):
```go ```go
func Sort(data Sorter) { func Sort(data Sorter) {
@@ -17,7 +17,7 @@ func Sort(data Sorter) {
} }
``` ```
`Sort` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ͳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Sorter` <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Щ<EFBFBD><D0A9><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Sort` 函数接收一个接口类型参数: `Sorter` ,它声明了这些方法:
```go ```go
type Sorter interface { type Sorter interface {
@@ -27,9 +27,9 @@ type Sorter interface {
} }
``` ```
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>е<EFBFBD> `int` <EFBFBD><EFBFBD><EFBFBD><EFBFBD>˵Ҫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ķ<EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD>Ҫ<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD> `int`<EFBFBD><EFBFBD>`i` <EFBFBD><EFBFBD> `j` <EFBFBD><EFBFBD>ʾԪ<EFBFBD>ص<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͵ġ<EFBFBD> 参数中的 `int` 不是说要排序的对象一定要是一组 `int``i` `j` 表示元素的整型索引,长度也是整型的。
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD> `int` <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>б<EFBFBD><D0B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD>һ<E9B6A8><D2BB><EFBFBD><EFBFBD><EFBFBD>Ͳ<EFBFBD><CDB2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><CAB5> `Sorter` <EFBFBD>ӿڵķ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 现在如果我们想对一个 `int` 数组进行排序,所有必须做的事情就是:为数组定一个类型并在它上面实现 `Sorter` 接口的方法:
```go ```go
type IntArray []int type IntArray []int
@@ -38,7 +38,7 @@ func (p IntArray) Less(i, j int) bool { return p[i] < p[j] }
func (p IntArray) Swap(i, j int) { p[i], p[j] = p[j], p[i] } func (p IntArray) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
``` ```
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӣ<EFBFBD> 下面是调用排序函数的一个具体例子:
```go ```go
data := []int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586} data := []int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586}
@@ -46,11 +46,11 @@ a := sort.IntArray(data) //conversion to type IntArray from package sort
sort.Sort(a) sort.Sort(a)
``` ```
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ġ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>еĴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `sort.go` <EFBFBD><EFBFBD> `sortmain.go` <EFBFBD><EFBFBD><EFBFBD>ҵ<EFBFBD><EFBFBD><EFBFBD> 完整的、可运行的代码可以在 `sort.go` `sortmain.go` 里找到。
ͬ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾÿ<EFBFBD>ܸ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ľṹ<EFBFBD><EFBFBD> `dayArray`. 同样的原理,排序函数可以用于一个浮点型数组,一个字符串数组,或者一个表示每周各天的结构体 `dayArray`.
ʾ<EFBFBD><EFBFBD> 11.6 sort.go<EFBFBD><EFBFBD> 示例 11.6 sort.go
```go ```go
package sort package sort
@@ -102,7 +102,7 @@ func IntsAreSorted(a []int) bool { return IsSorted(IntArray(a)) }
func StringsAreSorted(a []string) bool { return IsSorted(StringArray(a)) } func StringsAreSorted(a []string) bool { return IsSorted(StringArray(a)) }
``` ```
ʾ<EFBFBD><EFBFBD> 11.7 sortmain.go<EFBFBD><EFBFBD> 示例 11.7 sortmain.go
```go ```go
package main package main
@@ -173,17 +173,17 @@ func main() {
} }
``` ```
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 输出:
The sorted array is: [-5467984 -784 0 0 42 59 74 238 905 959 7586 7586 9845] The sorted array is: [-5467984 -784 0 0 42 59 74 238 905 959 7586 7586 9845]
The sorted array is: [ friday monday saturday sunday thursday tuesday wednesday] The sorted array is: [ friday monday saturday sunday thursday tuesday wednesday]
Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday Monday Tuesday Wednesday Thursday Friday Saturday
**<EFBFBD><EFBFBD>ע**<2A><> **备注**
`panic("fail")` <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֹͣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>µij<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϸ<EFBFBD><EFBFBD><EFBFBD>ο<EFBFBD> <20><>13<31>£<EFBFBD><C2A3><EFBFBD><EFBFBD><EFBFBD>ȻҲ<C8BB><D2B2><EFBFBD><EFBFBD><EFBFBD>ȴ<EFBFBD>ӡһ<D3A1><D2BB><EFBFBD><EFBFBD>Ϣ<EFBFBD><CFA2>Ȼ<EFBFBD><C8BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `os.Exit(1)` <EFBFBD><EFBFBD>ֹͣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `panic("fail")` 用于停止处于在非正常情况下的程序(详细请参考 第13章当然也可以先打印一条信息然后调用 `os.Exit(1)` 来停止程序。
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǽ<EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>˽<EFBFBD><EFBFBD>˽ӿڵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD>÷<EFBFBD>ʽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͵<EFBFBD><EFBFBD><EFBFBD><EFBFBD>򣬱<EFBFBD>׼<EFBFBD><EFBFBD><EFBFBD>Ѿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ص<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Բ<EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ظ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ˡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>Ե<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>`sort` <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>ӿڣ<D3BF> 上面的例子帮助我们进一步了解了接口的意义和使用方式。对于基本类型的排序,标准库已经提供了相关的排序函数,所以不需要我们再重复造轮子了。对于一般性的排序,`sort` 包定义了一个接口:
```go ```go
type Interface interface { type Interface interface {
@@ -193,36 +193,36 @@ type Interface interface {
} }
``` ```
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD><EFBFBD>ܽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ij<EFBFBD><EFBFBD>󷽷<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Sort(data Interface)` <20><><EFBFBD><EFBFBD><EFBFBD>Դ<EFBFBD><D4B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>򣬿<EFBFBD><F2A3ACBF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD>ֶ<EFBFBD><D6B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݣ<EFBFBD><DDA3>ǻ<EFBFBD><C7BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͣ<EFBFBD><CDA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>У<EFBFBD><D0A3><EFBFBD><EFBFBD><EFBFBD>Ҳ<EFBFBD><D2B2><EFBFBD><EFBFBD>ô<EFBFBD><C3B4><EFBFBD>ģ<EFBFBD><C4A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD> `int` <EFBFBD><EFBFBD> `string` <EFBFBD><EFBFBD><EFBFBD>н<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҳ<EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><EFBFBD>û<EFBFBD><EFBFBD>Զ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `dayArray` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 这个接口总结了需要用于排序的抽象方法,函数 `Sort(data Interface)` 用来对此类对象进行排序,可以用它们来实现对其他数据(非基本类型)进行排序。在上面的例子中,我们也是这么做的,不仅可以对 `int` `string` 序列进行排序,也可以对用户自定义类型 `dayArray` 进行排序。
**<EFBFBD><EFBFBD>ϰ 11.5** interfaces_ext.go<EFBFBD><EFBFBD> **练习 11.5** interfaces_ext.go
a). <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>չ<EFBFBD><EFBFBD><EFBFBD>򣬶<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Triangle`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><EFBFBD> `AreaInterface` <EFBFBD>ӿڡ<EFBFBD>ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>ض<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ε<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>в<EFBFBD><EFBFBD>ԣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>=0.5 * (<EFBFBD><EFBFBD> * <EFBFBD><EFBFBD>)<29><> a). 继续扩展程序,定义类型 `Triangle`,让它实现 `AreaInterface` 接口。通过计算一个特定三角形的面积来进行测试(三角形面积=0.5 * ( * 高)
b). <EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>½ӿ<EFBFBD> `PeriInterface`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD> `Perimeter` <EFBFBD>ӿڡ<EFBFBD><EFBFBD><EFBFBD> `Square` ʵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӿڣ<EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD> `Square` ʾ<><CABE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> b). 定义一个新接口 `PeriInterface`,它有一个 `Perimeter` 接口。让 `Square` 实现这个接口,并通过一个 `Square` 示例来测试它。
**<EFBFBD><EFBFBD>ϰ 11.6** point_interfaces.go<EFBFBD><EFBFBD> **练习 11.6** point_interfaces.go
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> 10.3 <EFBFBD>е<EFBFBD><EFBFBD><EFBFBD>ϰ point_methods.go<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD> `Magnitude`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Abs()`<EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Point`<EFBFBD><EFBFBD>`Point3` <EFBFBD><EFBFBD>`Polar` ʵ<EFBFBD>ִ˽ӿڡ<EFBFBD>ͨ<EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͱ<EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD>÷<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>point.go<67><6F>ͬ<EFBFBD><CDAC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 继续 10.3 中的练习 point_methods.go,定义接口 `Magnitude`,它有一个方法 `Abs()`。让 `Point``Point3` `Polar` 实现此接口。通过接口类型变量使用方法做point.go中同样的事情。
**<EFBFBD><EFBFBD>ϰ 11.7** float_sort.go / float_sortmain.go<EFBFBD><EFBFBD> **练习 11.7** float_sort.go / float_sortmain.go
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>11.7<EFBFBD><EFBFBD>ʾ<EFBFBD><EFBFBD>11.3/4<><34><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD> `float64`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڰ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Float64Array`<EFBFBD><EFBFBD>Ȼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><EFBFBD> `Sorter` <EFBFBD>ӿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `float64` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 类似11.7和示例11.3/4定义一个包 `float64`,并在包里定义类型 `Float64Array`,然后让它实现 `Sorter` 接口用来对 `float64` 数组进行排序。
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 另外提供如下方法:
- `NewFloat64Array()`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>25<EFBFBD><EFBFBD>Ԫ<EFBFBD>ص<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ο<EFBFBD>10.2<EFBFBD><EFBFBD> - `NewFloat64Array()`创建一个包含25个元素的数组变量参考10.2
- `List()`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `String()` <20><><EFBFBD><EFBFBD><EFBFBD>е<EFBFBD><D0B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ͳ<EFBFBD><CDB2><EFBFBD><EFBFBD><EFBFBD>ʽ<EFBFBD>ص<EFBFBD><D8B5><EFBFBD> `List()` <20><><EFBFBD><EFBFBD>ӡ<EFBFBD><D3A1><EFBFBD><EFBFBD>ο<EFBFBD>10.7<EFBFBD><EFBFBD> - `List()`:返回数组格式化后的字符串,并在 `String()` 方法中调用它,这样就不用显式地调用 `List()` 来打印数组(参考10.7
- `Fill()`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>10<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ο<EFBFBD>4.5.2.6<EFBFBD><EFBFBD> - `Fill()`创建一个包含10个随机浮点数的数组参考4.5.2.6
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>½<EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͵ı<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>򲢽<EFBFBD><EFBFBD>в<EFBFBD><EFBFBD>ԡ<EFBFBD> 在主程序中新建一个此类型的变量,然后对它排序并进行测试。
**<EFBFBD><EFBFBD>ϰ 11.8** sort.go/sort_persons.go<EFBFBD><EFBFBD> **练习 11.8** sort.go/sort_persons.go
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Person`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֶΣ<EFBFBD>`firstName` <EFBFBD><EFBFBD> `lastName`<EFBFBD><EFBFBD>Ϊ `[]Person` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Persons` <EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Persons` ʵ<EFBFBD><EFBFBD> `Sorter` <EFBFBD>ӿڲ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>в<EFBFBD><EFBFBD>ԡ<EFBFBD> 定义一个结构体 `Person`,它有两个字段:`firstName` `lastName`,为 `[]Person` 定义类型 `Persons` 。让 `Persons` 实现 `Sorter` 接口并进行测试。
## <EFBFBD><EFBFBD><EFBFBD><EFBFBD> ## 链接
- [Ŀ¼](directory.md) - [目录](directory.md)
- <EFBFBD><EFBFBD>һ<EFBFBD>ڣ<EFBFBD>[ʹ<EFBFBD>÷<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD>](11.6.md) - 上一节:[使用方法集与接口](11.6.md)
- <EFBFBD><EFBFBD>һ<EFBFBD>ڣ<EFBFBD>[<EFBFBD>ڶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д](11.8.md) - 下一节:[第二个例子:读和写](11.8.md)

View File

@@ -1,8 +1,8 @@
# 11.8 <EFBFBD>ڶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д # 11.8 第二个例子:读和写
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>к<EFBFBD><EFBFBD>ձ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֽڻ<EFBFBD><EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>׼<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>׼<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Լ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӡ<EFBFBD><EFBFBD>ܵ<EFBFBD><EFBFBD>ȵȣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>߶<EFBFBD>д<EFBFBD><EFBFBD><EFBFBD>ǵ<EFBFBD><EFBFBD>Զ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͡<EFBFBD>Ϊ<EFBFBD><EFBFBD><EFBFBD>Ǵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD>ã<EFBFBD>Go <20><>ȡ<EFBFBD><C8A1>һ<EFBFBD>µķ<C2B5>ʽ<EFBFBD><CABD><EFBFBD><EFBFBD>д<EFBFBD><D0B4><EFBFBD>ݡ<EFBFBD> 读和写是软件中很普遍的行为提起它们会立即想到读写文件、缓存比如字节或字符串切片、标准输入输出、标准错误以及网络连接、管道等等或者读写我们的自定义类型。为了是代码尽可能通用Go 采取了一致的方式来读写数据。
`io` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڶ<EFBFBD><EFBFBD><EFBFBD>д<EFBFBD>Ľӿڣ<EFBFBD>`io.Reader` <EFBFBD><EFBFBD> `io.Writer` `io` 包提供了用于读和写的接口:`io.Reader` `io.Writer`
```go ```go
type Reader interface { type Reader interface {
@@ -14,16 +14,16 @@ type Writer interface {
} }
``` ```
ֻҪ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><EFBFBD><EFBFBD>˶<EFBFBD>д<EFBFBD>ӿڣ<EFBFBD><EFBFBD> `Read()` <EFBFBD><EFBFBD> `Write` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϳ<EFBFBD><EFBFBD>Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD>ݣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݡ<EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD>ǿɶ<EFBFBD><EFBFBD>ģ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><EFBFBD> `io.Reader` <20>ӿڣ<D3BF><DAA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD>ֻ<EFBFBD><D6BB>һ<EFBFBD><D2BB>ǩ<EFBFBD><C7A9><EFBFBD><EFBFBD> `Read(p []byte) (n int, err error)` <20>ķ<EFBFBD><C4B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӵ<EFBFBD><D3B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ķ<EFBFBD><C4B6><EFBFBD><EFBFBD>϶<EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD>ݣ<EFBFBD><DDA3><EFBFBD><EFBFBD>Ѷ<EFBFBD><D1B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݷ<EFBFBD><DDB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>е<EFBFBD><D0B5>ֽ<EFBFBD><D6BD><EFBFBD>Ƭ<EFBFBD>У<EFBFBD>Ȼ<EFBFBD>󷵻ض<F3B7B5BB>ȡ<EFBFBD><C8A1><EFBFBD>ֽ<EFBFBD><D6BD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB> `error` <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>û<EFBFBD>д<EFBFBD><D0B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 'nil'<27><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ѿ<EFBFBD><D1BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>β<EFBFBD>ˣ<EFBFBD><CBA3><EFBFBD><E1B7B5> `io.EOF("EOF")`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD>Ĺ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>з<EFBFBD><EFBFBD><EFBFBD><EFBFBD>˴<EFBFBD><EFBFBD>󣬾ͻ᷵<EFBFBD>ؾ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƶأ<EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD>ǿ<EFBFBD>д<EFBFBD>ģ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><EFBFBD> `io.Writer` <20>ӿڣ<D3BF><DAA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD>Ҳֻ<D2B2><D6BB>һ<EFBFBD><D2BB>ǩ<EFBFBD><C7A9><EFBFBD><EFBFBD> `Write(p []byte) (n int, err error)` <20>ķ<EFBFBD><C4B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8><EFBFBD>ֽ<EFBFBD><D6BD><EFBFBD>Ƭ<EFBFBD>е<EFBFBD><D0B5><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><D0B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ķ<EFBFBD><C4B6><EFBFBD><EFBFBD>Ȼ<EFA3AC>󷵻<EFBFBD>ʵ<EFBFBD><CAB5>д<EFBFBD><D0B4><EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD><D6BD><EFBFBD>һ<EFBFBD><D2BB> `error` <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>û<EFBFBD>д<EFBFBD><D0B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `nil`<EFBFBD><EFBFBD><EFBFBD><EFBFBD> 只要类型实现了读写接口,提供 `Read()` `Write` 方法,就可以从它读取数据,或向它写入数据。一个对象要是可读的,它必须实现 `io.Reader` 接口,这个接口只有一个签名是 `Read(p []byte) (n int, err error)` 的方法,它从调用它的对象上读取数据,并把读到的数据放入参数中的字节切片中,然后返回读取的字节数和一个 `error` 对象,如果没有错误发生返回 'nil',如果已经到达输入的尾端,会返回 `io.EOF("EOF")`,如果读取的过程中发生了错误,就会返回具体的错误信息。类似地,一个对象要是可写的,它必须实现 `io.Writer` 接口,这个接口也只有一个签名是 `Write(p []byte) (n int, err error)` 的方法,它将指定字节切片中的数据写入调用它的对象里,然后返回实际写入的字节数一个 `error` 对象(如果没有错误发生就是 `nil`)。
`io` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Readers` <EFBFBD><EFBFBD> `Writers` <EFBFBD><EFBFBD><EFBFBD>Dz<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģ<EFBFBD>`bufio` <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˶<EFBFBD>Ӧ<EFBFBD>Ĵ<EFBFBD><C4B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>IJ<EFBFBD><C4B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڶ<EFBFBD>д `UTF-8` <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ı<EFBFBD><C4B1>ļ<EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>á<EFBFBD><C3A1><EFBFBD> <20><>12<31><32> <20><><EFBFBD>ǻῴ<C7BB><E1BFB4>ʵսʹ<D5BD><CAB9><EFBFBD><EFBFBD><EFBFBD>ǵĺܶ<C4BA><DCB6><EFBFBD><EFBFBD>ӡ<EFBFBD> `io` 包里的 `Readers` `Writers` 都是不带缓冲的,`bufio` 包里提供了对应的带缓冲的操作,在读写 `UTF-8` 编码的文本文件时它们尤其有用。在 第12章 我们会看在实战使用它们的很多例子。
<EFBFBD><EFBFBD>ʵ<EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>о<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܵ<EFBFBD>ʹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Щ<EFBFBD>ӿڣ<EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ø<EFBFBD>ͨ<EFBFBD>ã<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>κ<EFBFBD>ʵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Щ<EFBFBD>ӿڵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD>ö<EFBFBD>д<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 在实际编程中尽可能的使用这些接口,会使程序变得更通用,可以在任何实现了这些接口的类型上使用读写方法。
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD> `JPEG` ͼ<EFBFBD>ν<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD> `Reader` <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Խ<EFBFBD><D4BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ<EFBFBD><D4B4>̡<EFBFBD><CCA1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӻ<EFBFBD><D3BB><EFBFBD> `gzip` ѹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> `HTTP` <EFBFBD><EFBFBD><EFBFBD>е<EFBFBD> `JPEG`ͼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>κ<EFBFBD>ʵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>`Reader` <EFBFBD>ӿڵĶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 例如一个 `JPEG` 图形解码器,通过一个 `Reader` 参数,它可以解码来自磁盘、网络连接或以 `gzip` 压缩的 `HTTP` 流中的 `JPEG`图形数据,或者其他任何实现了`Reader` 接口的对象。
## <EFBFBD><EFBFBD><EFBFBD><EFBFBD> ## 链接
- [Ŀ¼](directory.md) - [目录](directory.md)
- <EFBFBD><EFBFBD>һ<EFBFBD>ڣ<EFBFBD>[<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӣ<EFBFBD>ʹ<EFBFBD><EFBFBD>Sorter<EFBFBD>ӿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>](11.7.md) - 上一节:[第一个例子使用Sorter接口排序](11.7.md)
- <EFBFBD><EFBFBD>һ<EFBFBD>ڣ<EFBFBD>[<EFBFBD>սӿ<EFBFBD>](11.9.md) - 下一节:[空接口](11.9.md)

View File

@@ -1,20 +1,20 @@
# 11.9 <EFBFBD>սӿ<EFBFBD> # 11.9 空接口
## 11.9.1 <EFBFBD><EFBFBD><EFBFBD><EFBFBD> ## 11.9.1 概念
**<EFBFBD>սӿڻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>С<EFBFBD>ӿ<EFBFBD>**<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>κη<CEBA><CEB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD>ֲ<EFBFBD><D6B2><EFBFBD><EFBFBD>κ<EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD> **空接口或者最小接口**不包含任何方法,它对实现不做任何要求:
```go ```go
type Any interface {} type Any interface {}
``` ```
<EFBFBD>κ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ͷ<EFBFBD>ʵ<EFBFBD><EFBFBD><EFBFBD>˿սӿڣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Java/C#` <EFBFBD><EFBFBD> `Object` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͣ<EFBFBD><EFBFBD><EFBFBD>`any` <EFBFBD><EFBFBD> `Any` <EFBFBD>ǿսӿ<EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>ܺõı<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><EFBFBD> 任何其他类型都实现了空接口(它不仅仅像 `Java/C#` `Object` 引用类型),`any` `Any` 是空接口一个很好的别名或缩写。
<EFBFBD>սӿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Java/C#` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ļ<EFBFBD><EFBFBD>`Object` <20><EFBFBD><E0A3AC><EFBFBD>ߵ<EFBFBD>Ŀ<EFBFBD><C4BF>Ҳ<EFBFBD><D2B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 空接口类似 `Java/C#` 中所有类的基类: `Object` 类,二者的目标也很相近。
<EFBFBD><EFBFBD><EFBFBD>Ը<EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>սӿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>͵ı<EFBFBD><EFBFBD><EFBFBD> `var val interface {}` <EFBFBD><EFBFBD><EFBFBD>κ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>͵<EFBFBD>ֵ<EFBFBD><EFBFBD> 可以给一个空接口类型的变量 `var val interface {}` 赋任何类型的值。
ʾ<EFBFBD><EFBFBD> 11.8 empty_interface.go<EFBFBD><EFBFBD> 示例 11.8 empty_interface.go
```go ```go
package main package main
@@ -56,16 +56,16 @@ func main() {
} }
``` ```
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 输出:
val has the value: 5 val has the value: 5
val has the value: ABC val has the value: ABC
val has the value: &{Rob Pike 55} val has the value: &{Rob Pike 55}
Type pointer to Person *main.Person Type pointer to Person *main.Person
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>У<EFBFBD><EFBFBD>ӿڱ<EFBFBD><EFBFBD><EFBFBD> `val` <20><><EFBFBD><EFBFBD><EFBFBD>θ<EFBFBD><CEB8><EFBFBD>һ<EFBFBD><D2BB> `int`<EFBFBD><EFBFBD>`string` <EFBFBD><EFBFBD> `Person` ʵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><EFBFBD>Ȼ<EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD> `type-swtich` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͡<EFBFBD>ÿ<EFBFBD><EFBFBD> `interface {}` <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD><DAB4><EFBFBD>ռ<EFBFBD><D5BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֳ<EFBFBD><D6B3><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E6B4A2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͣ<EFBFBD><CDA3><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E6B4A2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݻ<EFBFBD><DDBB><EFBFBD>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD><EFBFBD>ݵ<EFBFBD>ָ<EFBFBD> 在上面的例子中,接口变量 `val` 被依次赋予一个 `int``string` `Person` 实例的值,然后使用 `type-swtich` 来测试它的实际类型。每个 `interface {}` 变量在内存中占据两个字长:一个用来存储它包含的类型,另一个用来存储它包含的数据或者指向数据的指针。
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> emptyint_switch.go ˵<EFBFBD><EFBFBD><EFBFBD>˿սӿ<EFBFBD><EFBFBD><EFBFBD> `type-swtich` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `lambda` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>÷<EFBFBD><EFBFBD><EFBFBD> 例子 emptyint_switch.go 说明了空接口在 `type-swtich` 中联合 `lambda` 函数的用法:
```go ```go
package main package main
@@ -101,21 +101,21 @@ func main() {
} }
``` ```
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 输出:
any hello is a special String! any hello is a special String!
**<EFBFBD><EFBFBD>ϰ 11.9** simple_interface3.go<EFBFBD><EFBFBD> **练习 11.9** simple_interface3.go
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>ϰ11.2<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD> `gI` <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ٽ<EFBFBD><D9BD><EFBFBD> `Simpler` <20><><EFBFBD>͵IJ<CDB5><C4B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǽ<EFBFBD><C7BD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>սӿڲ<D3BF><DAB2><EFBFBD><EFBFBD><EFBFBD>Ȼ<EFBFBD><C8BB>ͨ<EFBFBD><CDA8><EFBFBD><EFBFBD><EFBFBD>Ͷ<EFBFBD><CDB6><EFBFBD><EFBFBD>жϲ<D0B6><CFB2><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD> `Simpler` <EFBFBD><EFBFBD><EFBFBD>͡<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `main` ʹ<EFBFBD><EFBFBD> `gI` ȡ<EFBFBD><EFBFBD> `fI` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȫ<EFBFBD><EFBFBD> 继续 练习11.2,在它中添加一个 `gI` 函数,它不再接受 `Simpler` 类型的参数,而是接受一个空接口参数。然后通过类型断言判断参数是否是 `Simpler` 类型。最后在 `main` 使用 `gI` 取代 `fI` 函数并调用它。确保你的代码足够安全。
## 11.9.2 <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͬ<EFBFBD><EFBFBD><EFBFBD>ͱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ## 11.9.2 构建通用类型或包含不同类型变量的数组
<EFBFBD><EFBFBD> 7.6.6 <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `int` <EFBFBD><EFBFBD><EFBFBD>`float` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Լ<EFBFBD> `string` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ô<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͵<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>أ<EFBFBD><EFBFBD>Dz<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>DZ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Լ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD> 7.6.6 中我们看到了能被搜索和排序的 `int` 数组、`float` 数组以及 `string` 数组,那么对于其他类型的数组呢,是不是我们必须得自己编程实现它们?
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֪<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ô<EFBFBD><EFBFBD><EFBFBD>ˣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD>ʹ<EFBFBD>ÿսӿڡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ǹ<EFBFBD><EFBFBD>սӿڶ<EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Element`<EFBFBD><EFBFBD>`type Element interface{}` 现在我们知道该怎么做了,就是通过使用空接口。让我们给空接口定一个别名类型 `Element``type Element interface{}`
Ȼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͵Ľṹ<EFBFBD><EFBFBD> `Vector`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD> `Element` <20><><EFBFBD><EFBFBD>Ԫ<EFBFBD>ص<EFBFBD><D8B5><EFBFBD>Ƭ<EFBFBD><C6AC> 然后定义一个容器类型的结构体 `Vector`,它包含一个 `Element` 类型元素的切片:
```go ```go
type Vector struct { type Vector struct {
@@ -123,7 +123,7 @@ type Vector struct {
} }
``` ```
`Vector` <EFBFBD><EFBFBD><EFBFBD>ܷ<EFBFBD><EFBFBD>κ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>͵ı<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD>κ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ͷ<EFBFBD>ʵ<EFBFBD><EFBFBD><EFBFBD>˿սӿڣ<EFBFBD>ʵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Vector` <20><><EFBFBD>ŵ<EFBFBD>ÿ<EFBFBD><C3BF>Ԫ<EFBFBD>ؿ<EFBFBD><D8BF><EFBFBD><EFBFBD>Dz<EFBFBD>ͬ<EFBFBD><CDAC><EFBFBD>͵ı<CDB5><C4B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB> `At()` <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڷ<EFBFBD><DAB7>ص<EFBFBD> `i` <EFBFBD><EFBFBD>Ԫ<EFBFBD>أ<EFBFBD> `Vector` 里能放任何类型的变量,因为任何类型都实现了空接口,实际上 `Vector` 里放的每个元素可以是不同类型的变量。我们为它定义一个 `At()` 方法用于返回第 `i` 个元素:
```go ```go
func (p *Vector) At(i int) Element { func (p *Vector) At(i int) Element {
@@ -131,7 +131,7 @@ func (p *Vector) At(i int) Element {
} }
``` ```
<EFBFBD>ٶ<EFBFBD>һ<EFBFBD><EFBFBD> `Set()` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>õ<EFBFBD> `i` <20><>Ԫ<EFBFBD>ص<EFBFBD>ֵ<EFBFBD><D6B5> 再定一个 `Set()` 方法用于设置第 `i` 个元素的值:
```go ```go
func (p *Vector) Set(i int, e Element) { func (p *Vector) Set(i int, e Element) {
@@ -139,26 +139,26 @@ func (p *Vector) Set(i int, e Element) {
} }
``` ```
`Vector` <EFBFBD>д洢<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ԫ<EFBFBD>ض<EFBFBD><EFBFBD><EFBFBD> `Element` <20><><EFBFBD>ͣ<EFBFBD>Ҫ<EFBFBD>õ<EFBFBD><C3B5><EFBFBD><EFBFBD>ǵ<EFBFBD>ԭʼ<D4AD><CABC><EFBFBD>ͣ<EFBFBD>unboxing<6E><67><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E4A3A9>Ҫ<EFBFBD>õ<EFBFBD><C3B5><EFBFBD><EFBFBD>Ͷ<EFBFBD><CDB6>ԡ<EFBFBD>TODO<EFBFBD><EFBFBD>The compiler rejects assertions guaranteed to fail<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ͷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>ִ<EFBFBD>У<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Vector` 中存储的所有元素都是 `Element` 类型要得到它们的原始类型unboxing拆箱需要用到类型断言。TODOThe compiler rejects assertions guaranteed to fail,类型断言总是在运行时才执行,因此它会产生运行时错误。
**<EFBFBD><EFBFBD>ϰ 11.10** min_interface.go / minmain.go<EFBFBD><EFBFBD> **练习 11.10** min_interface.go / minmain.go
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>11.7<EFBFBD>п<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Sorter` <20>ӿڣ<D3BF><DAA3><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB> `Miner` <20>ӿڲ<D3BF>ʵ<EFBFBD><CAB5>һЩ<D2BB><D0A9>Ҫ<EFBFBD>IJ<EFBFBD><C4B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Min` <EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD> `Miner` <EFBFBD><EFBFBD><EFBFBD>ͱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD>ϣ<EFBFBD>Ȼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ؼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>С<EFBFBD><EFBFBD>Ԫ<EFBFBD>ء<EFBFBD> 仿照11.7中开发的 `Sorter` 接口,创建一个 `Miner` 接口并实现一些必要的操作。函数 `Min` 接受一个 `Miner` 类型变量的集合,然后计算并返回集合中最小的元素。
## 11.9.3 <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƭ<EFBFBD><EFBFBD><EFBFBD>սӿ<EFBFBD><EFBFBD><EFBFBD>Ƭ ## 11.9.3 复制数据切片至空接口切片
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD> `myType` <EFBFBD><EFBFBD><EFBFBD>͵<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƭ<EFBFBD>е<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݸ<EFBFBD><EFBFBD>Ƶ<EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>սӿ<EFBFBD><EFBFBD><EFBFBD>Ƭ<EFBFBD>У<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƣ<EFBFBD> 假设你有一个 `myType` 类型的数据切片,你想将切片中的数据复制到一个空接口切片中,类似:
```go ```go
var dataSlice []myType = FuncReturnSlice() var dataSlice []myType = FuncReturnSlice()
var interfaceSlice []interface{} = dataSlice var interfaceSlice []interface{} = dataSlice
``` ```
<EFBFBD><EFBFBD>ϧ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ô<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>`cannot use dataSlice (type []myType) as type []interface { } in assignment` 可惜不能这么做,编译时会出错:`cannot use dataSlice (type []myType) as type []interface { } in assignment`
ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD><EFBFBD>еIJ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Dz<EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>ģ<EFBFBD><EFBFBD>ο<EFBFBD>[http://golang.org/doc/go_spec.html](http://golang.org/doc/go_spec.html)<EFBFBD><EFBFBD><EFBFBD><EFBFBD> 原因是它们俩在内存中的布局是不一样的(参考[http://golang.org/doc/go_spec.html](http://golang.org/doc/go_spec.html))。
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD> `for-range` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʽ<EFBFBD>ظ<EFBFBD><EFBFBD>ƣ<EFBFBD> 必须使用 `for-range` 语句来一个一个显式地复制:
```go ```go
var dataSlice []myType = FuncReturnSlice() var dataSlice []myType = FuncReturnSlice()
@@ -168,11 +168,11 @@ for ix, d := range dataSlice {
} }
``` ```
## 11.9.4 ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͵Ľڵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݽṹ ## 11.9.4 通用类型的节点数据结构
<EFBFBD><EFBFBD>10.1<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>б<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݽṹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǵĶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD>ֽнڵ<EFBFBD><EFBFBD>ĵݹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͣ<EFBFBD><EFBFBD>ڵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD>ij<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͵<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֶΡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڿ<EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD>ÿսӿ<EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֶε<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ǿ<EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><EFBFBD>ͨ<EFBFBD>õĴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>IJ<EFBFBD><EFBFBD>ִ<EFBFBD><EFBFBD>룺ͨ<EFBFBD>ö<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>սڵ<EFBFBD><EFBFBD><EFBFBD> `NewNode` <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݵ<EFBFBD> `SetData` <EFBFBD><EFBFBD><EFBFBD><EFBFBD>. 10.1中我们遇到了诸如列表和树这样的数据结构,在它们的定义中使用了一种叫节点的递归结构体类型,节点包含一个某种类型的数据字段。现在可以使用空接口作为数据字段的类型,这样我们就能写出通用的代码。下面是实现一个二叉树的部分代码:通用定义、用于创建空节点的 `NewNode` 方法,及设置数据的 `SetData` 方法.
ʾ<EFBFBD><EFBFBD> 11.10 node_structures.go: 示例 11.10 node_structures.go:
```go ```go
package main package main
@@ -207,11 +207,11 @@ func main() {
} }
``` ```
## 11.9.5 <EFBFBD>ӿڵ<EFBFBD><EFBFBD>ӿ<EFBFBD> ## 11.9.5 接口到接口
һ<EFBFBD><EFBFBD><EFBFBD>ӿڵ<EFBFBD>ֵ<EFBFBD><EFBFBD><EFBFBD>Ը<EFBFBD>ֵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>ӿڱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֻҪ<EFBFBD>ײ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><EFBFBD><EFBFBD>˱<EFBFBD>Ҫ<EFBFBD>ķ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD>м<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģ<EFBFBD>ת<EFBFBD><EFBFBD>ʧ<EFBFBD>ܻᵼ<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 'Go' <20><><EFBFBD>Զ<EFBFBD>̬<EFBFBD><CCAC>һ<EFBFBD><EFBFBD><E6A3AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Ruby` <EFBFBD><EFBFBD> `Python` <EFBFBD><EFBFBD>Щ<EFBFBD><EFBFBD>̬<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƚϡ<EFBFBD> 一个接口的值可以赋值给另一个接口变量,只要底层类型实现了必要的方法。这个转换是在运行时进行检查的,转换失败会导致一个运行时错误:这是 'Go' 语言动态的一面,可以那它和 `Ruby` `Python` 这些动态语言相比较。
<EFBFBD>ٶ<EFBFBD><EFBFBD><EFBFBD> 假定:
```go ```go
var ai AbsInterface // declares method Abs() var ai AbsInterface // declares method Abs()
@@ -223,18 +223,18 @@ pp := new(Point) // say *Point implements Abs, Sqr
var empty interface{} var empty interface{}
``` ```
<EFBFBD><EFBFBD>ô<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ͷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǺϷ<EFBFBD><EFBFBD>ģ<EFBFBD> 那么下面的语句和类型断言是合法的:
```go ```go
empty = pp // everything satisfies empty empty = pp // everything satisfies empty
ai = empty.(AbsInterface) // underlying value pp implements Abs() ai = empty.(AbsInterface) // underlying value pp implements Abs()
// (runtime failure otherwise) // (runtime failure otherwise)
si = ai.(SqrInterface) // *Point has Sqr() even though AbsInterface doesn<EFBFBD><EFBFBD>t si = ai.(SqrInterface) // *Point has Sqr() even though AbsInterface doesnt
empty = si // *Point implements empty set empty = si // *Point implements empty set
// Note: statically checkable so type assertion not necessary. // Note: statically checkable so type assertion not necessary.
``` ```
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ǻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>õ<EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӣ<EFBFBD> 下面是函数调用的一个例子:
```go ```go
type myPrintInterface interface { type myPrintInterface interface {
@@ -246,10 +246,10 @@ func f3(x myInterface) {
} }
``` ```
`x` ת<EFBFBD><EFBFBD>Ϊ `myPrintInterface` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȫ<EFBFBD><EFBFBD>̬<EFBFBD>ģ<EFBFBD>ֻҪ `x` <20>ĵײ<C4B5><D7B2><EFBFBD><EFBFBD>ͣ<EFBFBD><CDA3><EFBFBD>̬<EFBFBD><CCAC><EFBFBD>ͣ<EFBFBD><CDA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `print` <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>þͿ<C3BE><CDBF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>С<EFBFBD> `x` 转换为 `myPrintInterface` 类型是完全动态的:只要 `x` 的底层类型(动态类型)定义了 `print` 方法这个调用就可以正常运行。
## <EFBFBD><EFBFBD><EFBFBD><EFBFBD> ## 链接
- [Ŀ¼](directory.md) - [目录](directory.md)
- <EFBFBD><EFBFBD>һ<EFBFBD>ڣ<EFBFBD>[<EFBFBD>ڶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д](11.8.md) - 上一节:[第二个例子:读和写](11.8.md)
- <EFBFBD><EFBFBD>һ<EFBFBD>ڣ<EFBFBD>[<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>](11.10.md) - 下一节:[反射包](11.10.md)