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

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


admin.Notify()

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

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

所以通过外部类型来调用 Notify 方法,本质上是内部类型的方法。

下面是 Go 语言中内部类型方法集提升的规则:

给定一个结构体类型 S 和一个命名为 T 的类型,方法提升像下面规定的这样被包含在结构体方法集中:

1.如果 S 包含一个匿名字段 T,S 和 *S 的方法集都包含接受者为 T 的方法提升。

这条规则说的是当我们嵌入一个类型,嵌入类型的接受者为值类型的方法将被提升,可以被外部类型的值和指针调用。

1.对于 *S 类型的方法集包含接受者为 *T 的方法提升

这条规则说的是当我们嵌入一个类型,可以被外部类型的指针调用的方法集只有嵌入类型的接受者为指针类型的方法集,也就是说,当外部类型使用指针调用内部类型的方法时,只有接受者为指针类型的内部类型方法集将被提升。

1.如果 S 包含一个匿名字段 *T,S 和 *S 的方法集都包含接受者为 T 或者 *T 的方法提升

这条规则说的是当我们嵌入一个类型的指针,嵌入类型的接受者为值类型或指针类型的方法将被提升,可以被外部类型的值或者指针调用。

这就是语言规范里方法提升中仅有的三条规则,我根据这个推导出一条规则:

1.如果 S 包含一个匿名字段 T,S 的方法集不包含接受者为 *T 的方法提升。

这条规则说的是当我们嵌入一个类型,嵌入类型的接受者为指针的方法将不能被外部类型的值访问。这也是跟我们上面陈述的接口规则一致。

回答开头的问题

现在我们可以写程序来回答开头提出的两个问题了,首先我们让 Admin 类型实现 Notifier 接口:


func (a *Admin) Notify() error {
  log.Printf("Admin: Sending Admin Email To %s<%s>n",
      a.Name,
      a.Email)
     
  return nil
}

Admin 类型实现的接口显示一条 admin 方面的信息。当我们使用 Admin 类型的指针去调用函数 SendNotification 时,这将帮助我们确定到底是哪个接口实现被调用了。

现在创建一个 Admin 类型的值并把它的地址传入 SendNotification 函数,来看看发生了什么:


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

// Output