Go语言中的方法、接口和嵌入类型详解

2019-11-10 08:57:03于海丽

语言规范里只有这两条规则,我通过这两条规则得出了符合我们例子的规则:

1.类型 T 的可调用方法集不包含接受者为 *T 的方法

我们碰巧赶上了我推断出的这条规则,所以编译器会报错。Notify 方法使用指针类型作为接受者而我们却通过值类型来调用该方法。解决办法也很简单,我们只需要传入 User 值的地址到 SendNotification 函数就好了:

func main() {
  user := &User{
    Name:  "AriesDevil",
    Email: "ariesdevil@xxoo.com",
  }
 
  SendNotification(user)
}

// Output:
User: Sending User Email To AriesDevil<ariesdevil@xxoo.com>

详细代码:http://play.golang.org/p/kEKzyTfLjA

嵌入类型

结构体类型可以包含匿名或者嵌入字段。也叫做嵌入一个类型。当我们嵌入一个类型到结构体中时,该类型的名字充当了嵌入字段的字段名。

下面定义一个新的类型然后把我们的 User 类型嵌入进去:


type Admin struct {
  User
  Level  string
}

我们定义了一个新类型 Admin 然后把 User 类型嵌入进去,注意这个不叫继承而叫组合。 User 类型跟 Admin 类型没有关系。

我们来改变一下 main 函数,创建一个 Admin 类型的变量并把变量的地址传入 SendNotification 函数中:

func main() {
  admin := &Admin{
    User: User{
      Name:  "AriesDevil",
      Email: "ariesdevil@xxoo.com",
    },
    Level: "master",
  }
 
  SendNotification(admin)
}

// Output
User: Sending User Email To AriesDevil<ariesdevil@xxoo.com>

详细代码:http://play.golang.org/p/ivzzzk78TC

事实证明,我们可以 Admin 类型的一个指针来调用 SendNotification 函数。现在 Admin 类型也通过来自嵌入的 User 类型的方法提升实现了该接口。

如果 Admin 类型包含了 User 类型的字段和方法,那么它们在结构体中的关系是怎么样的呢?

当我们嵌入一个类型,这个类型的方法就变成了外部类型的方法,但是当它被调用时,方法的接受者是内部类型(嵌入类型),而非外部类型。— Effective Go

因此嵌入类型的名字充当着字段名,同时嵌入类型作为内部类型存在,我们可以使用下面的调用方法:


admin.User.Notify()

// Output
User: Sending User Email To AriesDevil<ariesdevil@xxoo.com>

详细代码:http://play.golang.org/p/0WL_5Q6mao

这儿我们通过类型名称来访问内部类型的字段和方法。然而,这些字段和方法也同样被提升到了外部类型: