# 2.6 组合 go支持组合,即一种结构体包含另外一个结构体。在一些语言中,这叫混入类或者特性。语言总是不能实现简明的组合机制。在java中: ```java public class Person { private String name; public String getName() { return this.name; } } public class Saiyan { // 这表明`Saiyan`有一个`person` private Person person; // 可以使用`person`调用方法 public String getName() { return this.person.getName(); } ... } ``` 这样语法太繁琐了。每个`Person`的方法在`Saiyan`中都被复写一遍。go避免这样繁琐的方式: ```go type Person struct { Name string } func (p *Person) Introduce() { fmt.Printf("Hi, I'm %s\n", p.Name) } type Saiyan struct { *Person Power int } // 使用: goku := &Saiyan{ Person: &Person{"Goku"}, Power: 9001, } goku.Introduce() ``` 结构体`Saiyan`有一个字段时`*Persion`类型。因此我们没有明确的给它一个字段名,我们可以间接的使用这个组合类型的字段和方法。然而,go编译器给会给该字段一个名字,认为这是完全有效的。 ```go goku := &Saiyan{ Person: &Person{"Goku"}, } fmt.Println(goku.Name) fmt.Println(goku.Person.Name) ``` 上面代码都将打印`Goku`。 组合优于继承吗?很多人都认为组合是一种更健壮的共享代码的方式。当你使用继承,你的类将和你的超类紧耦合,并且你最终更关注继承,而不是行为。 ## 2.6.1 重载 虽然重载不是针对结构体,但是也值得提及。简单来说,go不支持重载。因此你会看见(和写)很多函数诸如`Load`、`LoadById`和 `LoadByName`等等。 然而,因为匿名组合只是一个编译技巧,我们能“重写”一个组合类型的方法。例如,我们的结构体`Saiyan`可以定义自己的`Introduce`方法: ```go func (s *Saiyan) Introduce() { fmt.Printf("Hi, I'm %s. Ya!\n", s.Name) } ``` 这种组合版本总是可以通过`s.Person.Introduce()`调用`Introduce()`方法。 ## 链接