• 2.6 组合
    • 2.6.1 重载
    • 链接

    2.6 组合

    go支持组合,即一种结构体包含另外一个结构体。在一些语言中,这叫混入类或者特性。语言总是不能实现简明的组合机制。在java中:

    1. public class Person {
    2. private String name;
    3. public String getName() {
    4. return this.name;
    5. }
    6. }
    7. public class Saiyan {
    8. // 这表明`Saiyan`有一个`person`
    9. private Person person;
    10. // 可以使用`person`调用方法
    11. public String getName() {
    12. return this.person.getName();
    13. }
    14. ...
    15. }

    这样语法太繁琐了。每个Person的方法在Saiyan中都被复写一遍。go避免这样繁琐的方式:

    1. type Person struct {
    2. Name string
    3. }
    4. func (p *Person) Introduce() {
    5. fmt.Printf("Hi, I'm %s\n", p.Name)
    6. }
    7. type Saiyan struct {
    8. *Person
    9. Power int
    10. }
    11. // 使用:
    12. goku := &Saiyan{
    13. Person: &Person{"Goku"},
    14. Power: 9001,
    15. }
    16. goku.Introduce()

    结构体Saiyan有一个字段时*Persion类型。因此我们没有明确的给它一个字段名,我们可以间接的使用这个组合类型的字段和方法。然而,go编译器给会给该字段一个名字,认为这是完全有效的。

    1. goku := &Saiyan{
    2. Person: &Person{"Goku"},
    3. }
    4. fmt.Println(goku.Name)
    5. fmt.Println(goku.Person.Name)

    上面代码都将打印Goku

    组合优于继承吗?很多人都认为组合是一种更健壮的共享代码的方式。当你使用继承,你的类将和你的超类紧耦合,并且你最终更关注继承,而不是行为。

    2.6.1 重载

    虽然重载不是针对结构体,但是也值得提及。简单来说,go不支持重载。因此你会看见(和写)很多函数诸如LoadLoadByIdLoadByName等等。

    然而,因为匿名组合只是一个编译技巧,我们能“重写”一个组合类型的方法。例如,我们的结构体Saiyan可以定义自己的Introduce方法:

    1. func (s *Saiyan) Introduce() {
    2. fmt.Printf("Hi, I'm %s. Ya!\n", s.Name)
    3. }

    这种组合版本总是可以通过s.Person.Introduce()调用Introduce()方法。

    链接

    • 目录
    • 上一节:结构体字段
    • 下一节:指针类型和值类型