mirror of
https://github.com/unknwon/the-way-to-go_ZH_CN.git
synced 2025-08-12 06:19:44 +08:00
fix encoding
This commit is contained in:
@@ -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)
|
||||||
|
104
eBook/11.1.md
104
eBook/11.1.md
@@ -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`。它本质上是一个指针,虽然不完全是一回事。指向接口值的指针是非法的,它们不仅一点用也没有,还会导致代码错误。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
<EFBFBD>˴<EFBFBD><EFBFBD>ķ<EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ġ<EFBFBD>
|
此处的方法指针表是通过运行时反射能力构建的。
|
||||||
|
|
||||||
<EFBFBD><EFBFBD><EFBFBD>ͣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ṹ<EFBFBD>壩ʵ<EFBFBD>ֽӿڷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>еķ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ÿһ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<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)
|
||||||
|
|
||||||
|
@@ -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)
|
@@ -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)
|
@@ -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)
|
@@ -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)
|
@@ -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)
|
@@ -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)
|
@@ -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)
|
@@ -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:拆箱)需要用到类型断言。TODO:The 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 doesn’t
|
||||||
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)
|
Reference in New Issue
Block a user