diff --git a/eBook/11.12.md b/eBook/11.12.md index 15b12d4..e0a450d 100644 --- a/eBook/11.12.md +++ b/eBook/11.12.md @@ -221,8 +221,94 @@ func (b Bar) ImplementsFooer() {} func (b Bar) Foo() {} ## 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) \ No newline at end of file diff --git a/eBook/11.13.md b/eBook/11.13.md new file mode 100644 index 0000000..b0b9d33 --- /dev/null +++ b/eBook/11.13.md @@ -0,0 +1,2 @@ +# 总结:Go 中的面向对象 + diff --git a/eBook/directory.md b/eBook/directory.md index 504a83d..15939cf 100644 --- a/eBook/directory.md +++ b/eBook/directory.md @@ -105,6 +105,8 @@ - 11.9 [空接口](11.9.md) - 11.10 [反射包](11.10.md) - 11.11 [Printf 和反射](11.11.md) + - 11.12 [接口与动态类型](11.12.md) + - 11.13 [总结:Go 中的面向对象](11.13.md) ## 第三部分:Go 高级编程