From 42b7c21a7cda330e550be078f2c1fa02505df87a Mon Sep 17 00:00:00 2001 From: leisore Date: Fri, 7 Aug 2015 13:53:48 +0800 Subject: [PATCH] * 10.6.6 OK --- eBook/10.6.md | 84 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 82 insertions(+), 2 deletions(-) diff --git a/eBook/10.6.md b/eBook/10.6.md index 556c710..820d89b 100644 --- a/eBook/10.6.md +++ b/eBook/10.6.md @@ -334,9 +334,89 @@ func main() { 对象的字段(属性)不应该由2个或2个以上的不同线程在同一时间去改变。如果在程序发生这种情况,为了安全并发访问,可以使用包sync(参考9.3)中的方法。在14.17我们会通过goroutines和channels探索另一种方式。 -** 嵌入类型上的方法和继承 -// TODO +** 10.6.5 内嵌类型的方法和继承 +当一个匿名类型被内嵌在结构体中时,匿名类型的可见方法也同样被内嵌---在效果上等同于外层类型*继承*了这些方法:*将父类型放在子类型中来实现亚型*。这个机制提供了一种简单的方式来模拟经典OO语言中的子类和继承相关的效果,也类似Ruby中的混入(mixin)。 + +下面是一个示例(可以在练习 10.8中进一步学习):假定有一个Engine接口类型,一个Car结构体类型,它包含一个Engine类型的匿名字段: + +```go +type Engine interface { + Start() + Stop() +} + +type Car struct { + Engine +} +``` + +我们可以构建如下的代码: + +```go +func (c *Car) GoToWorkIn() { + // get in car + c.Start() + // drive to work + c.Stop() + // get out of car +} +``` + +下面是method3.go的完整例子,它展示了内嵌结构体上的方法可以直接在外层类型的实例上调用: + +```go +package main + +import ( + "fmt" + "math" +) + +type Point struct { + x, y float64 +} + +func (p *Point) Abs() float64 { + return math.Sqrt(p.x*p.x + p.y*p.y) +} + +type NamedPoint struct { + Point + name string +} + +func main() { + n := &NamedPoint{Point{3, 4}, "Pythagoras"} + fmt.Println(n.Abs()) // 打印5 +} +``` + +内嵌将一个已存在类型的字段和方法注入到了另一个类型里:匿名字段上的方法“晋升”成为了外层类型的方法。当然类型可以有只作用于本身实例而不作用于内嵌“父”类型上的方法, + +可以覆写方法(像字段一样):和内嵌类型方法具有同样名字的外层类型的方法会覆写内嵌类型对应的方法。在Listing 10.18—method4.go中添加: + +```go +func (n *NamedPoint) Abs() float64 { + return n.Point.Abs() * 100. +} +``` + +现在`fmt.Println(n.Abs())`会打印500. + +因为一个结构体可以嵌入多个匿名类型,所以实际上我们可以有一个简单版本的多重继承,就像:`type Child struct { Father; Mother}`。在10.6.7中会进一步讨论这个问题。 + +结构体内嵌和自己在同一个包中的结构体时,可以彼此访问对方所有的字段和方法。 + +**练习 10.8**:inheritance_car.go + +创建一个上面Car和Engine可运行的例子,并且给Car类型一个wheelCount字段和一个numberOfWheels()方法。 + +创建一个Mercedes类型,它内嵌Car,并新建Mercedes的一个实例,然后调用它的方法。 + +然后仅在Mercedes类型上创建方法sayHiToMerkel()并调用它。 + +** 10.6.6 ## 链接 - [目录](directory.md)