Go基础编程:嵌入类型

Go语言允许用户扩展或者修改已有类型的行为。这个功能对代码复用很重要,在修改已有类型以符合新类型的时候也很重要。这个功能是通过嵌入类型完成的。嵌入类型是将已有的类型直接声明在新的结构类型里。被嵌入的类型被称为新的外部类型的内部类型。
通过嵌入类型,与内部类型相关的标识符会提升到外部类型上。这些被提升的标识符就像直接声明在外部类型里的标识符一样,也是外部类型的一部分。这样外部类型就组合了内部类型包含的所有属性,并且可以添加新的字段和方法。外部类型也可以通过声明与内部类型标识符同名的标识符来覆盖内部标识符的字段或者方法。这就是扩展或者修改已有类型的方法。
下面是一个示例程序演示嵌入类型的基本方法

package main
import "fmt"
//在程序里定义一个用户类型
type user struct{
    name string
    email string
}
 
func (u *user)notify(){
    fmt.Printf("Sending user email to %s<%s>\n",u.name,u.email)
}
 
type admin struct {
    user //嵌入user类型
    level string
}
 
func main(){
    ad:=admin{
        user:user{
            name:"john smith",
            email:"john@yahoo.com",
        },
        level:"super",
    }
    //我们可以直接访问内部类型的方法
    ad.user.notify()//Sending user email to john smith<john@yahoo.com>
    //内部类型的方法被提升到外部类型
    ad.notify()//Sending user email to john smith<john@yahoo.com>
}

要嵌入一个类型,只需要声明这个类型的名字就可以了。注意声明字段和嵌入类型在语法上的不同。通过内部类型的名字可以访问内部类型,如ad.user.notify()。不过,借助于内部类型的提升,notify方法也可以直接通过ad变量来访问,如ad.notify()。
由于内部类型的标识符提升到了外部类型,我们可以直接通过外部类型的值来访问内部类型的标识符。让我们修改一下这个例子,加入一个接口,如下所示

package main
import "fmt"
type notifier interface{
    notify()
}
//在程序里定义一个用户类型
type user struct{
    name string
    email string
}
 
func (u *user)notify(){
    fmt.Printf("Sending user email to %s<%s>\n",u.name,u.email)
}
 
type admin struct {
    user //嵌入类型
    level string
}
 
func main(){
    ad:=admin{
        user:user{
            name:"john smith",
            email:"john@yahoo.com",
        },
        level:"super",
    }
    //给admin用户发送一个通知,用于实现接口的内部类型的方法,被提升到外部类型
    sendNotification(&ad)//Sending user email to john smith<john@yahoo.com>
}
func sendNotification(n notifier){
    n.notify()
}

我们创建了一个名为ad的变量,其类型是外部类型admin。这个类型内部嵌入了user类型。之后将这个外部类型变量的地址传给sendNotification函数。编译器认为这个指针实现了notifier接口,并接受了这个值得传递。不过程序中admin类型并没有实现这个接口。由于内部类型的提升,内部类型实现的接口会自动提升到外部类型。这意味着由于内部类型的实现,外部类型也同样实现了这个接口。
如果外部类型并不需要使用内部类型的实现,而想要自己的一套实现,下面另一个示例程序解决了这个问题。

package main
import "fmt"
type notifier interface{
    notify()
}
//在程序里定义一个用户类型
type user struct{
    name string
    email string
}
 
func (u *user)notify(){
    fmt.Printf("Sending user email to %s<%s>\n",u.name,u.email)
}
 
type admin struct {
    user //嵌入类型
    level string
}
 
func (a *admin)notify(){
    fmt.Printf("Sending admin email to %s<%s>\n",a.name,a.email)
}
func main(){
    ad:=admin{
        user:user{
            name:"john smith",
            email:"john@yahoo.com",
        },
        level:"super",
    }
    //给admin用户发送一个通知,接口的嵌入内部类型实现并没有被提升到外部类型
    sendNotification(&ad)// Sending admin email to john smith<john@yahoo.com>

    //我们可以直接访问内部类型的放法
    ad.user.notify()// Sending user email to john smith<john@yahoo.com>

    //内部类型的方法没有被提升
    ad.notify()  // Sending admin email to john smith<john@yahoo.com>
}
 
func sendNotification(n notifier){
    n.notify()
}

这表明,如果外部类型实现了notify方法,内部类型的实现就不会被提升。不过内部类型的值一直存在,因此还可以通过直接访问内部类型的值,来调用没有被提升的内部类型实现的方法。

發表回覆

你的電郵地址並不會被公開。 必要欄位標記為 *