mirror of
https://github.com/unknwon/the-way-to-go_ZH_CN.git
synced 2025-08-12 05:33:04 +08:00
完成11.12翻译
This commit is contained in:
@@ -221,8 +221,94 @@ func (b Bar) ImplementsFooer() {} func (b Bar) Foo() {}
|
|||||||
|
|
||||||
## 11.12.5 空接口和函数重载
|
## 11.12.5 空接口和函数重载
|
||||||
|
|
||||||
|
在 6.1 节中, 我们看到函数重载是不被允许的。在 Go 语言中函数重载可以用可变参数 `...T` 作为函数最后一个参数来实现(参见 6.3 节)。如果我们把 T 换为空接口,那么可以知道任何类型的变量都是满足 T (空接口)类型的,这样就允许我们传递任何数据任何类型的参数给函数,即重载的实际含义。
|
||||||
|
|
||||||
|
函数 `fmt.Printf` 就是这样做的:
|
||||||
|
|
||||||
|
```go
|
||||||
|
fmt.Printf(format string, a ...interface{}) (n int, errno error)
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
这个函数通过枚举 `slice` 类型的实参动态确定所有参数的类型。并查看每个类型是否实现了 `String()` 方法,如果是就用于产生输出信息。我们可以返回 11.10 节查看这些细节。
|
||||||
|
|
||||||
|
## 11.12.6 接口的继承
|
||||||
|
|
||||||
|
当一个类型包含(内嵌)另一个类型(实现了一个或多个接口)的指针时,这个类型就可以使用(另一个类型)所有的接口方法。
|
||||||
|
|
||||||
|
例如:
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Task struct {
|
||||||
|
Command string
|
||||||
|
*log.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
这个类型的工厂方法像这样:
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewTask(command string, logger *log.Logger) *Task {
|
||||||
|
return &Task{command, logger}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
当 `log.Logger` 实现了 `Log()` 方法后,Task 的实例 task 就可以调用该方法:
|
||||||
|
|
||||||
|
```go
|
||||||
|
task.Log()
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
类型可以通过继承多个接口来提供像 `多重继承` 一样的特性:
|
||||||
|
|
||||||
|
```go
|
||||||
|
type ReaderWriter struct {
|
||||||
|
*io.Reader
|
||||||
|
*io.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
上面概述的原理被应用于整个 Go 包,多态用得越多,代码就相对越少(参见 12.8 节)。这被认为是 Go 编程的一种重要的最佳实践。
|
||||||
|
|
||||||
|
有用的接口可以在开发的过程中被归纳出来。添加新接口非常容易,因为已有的类型不用变动(仅仅需要实现新接口的方法)。已有的函数可以扩展为使用接口类型的约束性参数:通常只有函数签名需要改变。对比基于类的 OO 类型的语言在这种情况下则需要适应整个类层次结构的变化。
|
||||||
|
|
||||||
|
**练习 11.11**:[map_function_interface.go](exercises/chapter_11/map_function_interface.go):
|
||||||
|
|
||||||
|
在练习 7.13 中我们定义了一个 map 函数来使用 int 切片 (map_function.go)。
|
||||||
|
|
||||||
|
通过空接口和类型断言,现在我们可以写一个可以应用于许多类型的 `泛型` 的 map 函数,为 int 和 string 构建一个把 int 值加倍和连接字符串值的 map 函数 `mapFunc`。
|
||||||
|
|
||||||
|
提示:为了可读性可以定义一个 interface{} 的别名,比如:type obj interface{}
|
||||||
|
|
||||||
|
**练习 11.12**:[map_function_interface_var.go](exercises/chapter_11/map_function_interface_var.go):
|
||||||
|
|
||||||
|
稍微改变练习 11.9,允许 `mapFunc` 接收不定数量的 items。
|
||||||
|
|
||||||
|
**练习 11.13**:[main_stack.go—stack/stack_general.go](exercises/chapter_11/main_stack.go—stack/stack_general.go):
|
||||||
|
|
||||||
|
在练习 10.10 和 10.11 中我们开发了一些栈结构类型。但是它们被限制为某种固定的内建类型。现在用一个元素类型是 interface{}(空接口)的切片开发一个通用的栈类型。
|
||||||
|
|
||||||
|
实现下面的栈方法:
|
||||||
|
|
||||||
|
```go
|
||||||
|
Len() int
|
||||||
|
IsEmpty() bool
|
||||||
|
Push(x interface{})
|
||||||
|
Pop() (x interface{}, error)
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
写一个 `Pop()` 改变栈并返回最顶部的元素;并写一个 `Top()` 只返回最顶部元素。
|
||||||
|
|
||||||
|
在主程序中构建一个充满不同类型元素的栈,然后弹出并打印所有元素的值。
|
||||||
|
|
||||||
|
|
||||||
|
## 链接
|
||||||
|
|
||||||
|
- [目录](directory.md)
|
||||||
|
- 上一节:[Printf 和反射](11.11.md)
|
||||||
|
- 下一节:[总结:Go 中的面向对象](11.13.md)
|
2
eBook/11.13.md
Normal file
2
eBook/11.13.md
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# 总结:Go 中的面向对象
|
||||||
|
|
@@ -105,6 +105,8 @@
|
|||||||
- 11.9 [空接口](11.9.md)
|
- 11.9 [空接口](11.9.md)
|
||||||
- 11.10 [反射包](11.10.md)
|
- 11.10 [反射包](11.10.md)
|
||||||
- 11.11 [Printf 和反射](11.11.md)
|
- 11.11 [Printf 和反射](11.11.md)
|
||||||
|
- 11.12 [接口与动态类型](11.12.md)
|
||||||
|
- 11.13 [总结:Go 中的面向对象](11.13.md)
|
||||||
|
|
||||||
## 第三部分:Go 高级编程
|
## 第三部分:Go 高级编程
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user