Go 嵌入类型

     文章转载地址:https://www.flysnow.org/2017/04/06/go-in-action-go-embedded-type.html

     嵌入类型或嵌套类型,这是一种可以把已有类型的声明嵌入到新的类型里的一种方式,这种功能对代码复用非常

重要

     在其他语言中,有继承的概念,但是在 Go 语言中没有继承的概念,Go 提倡的代码复用的方式是组合,所以,这

也是嵌入类型的意义所在,组合不是继承,所以,Go 才会更加灵活

type Reader interface {
	Read(p []byte) (n int, err error)
}

type Writer interface {
	Write(p []byte) (n int,err error)
}

type Closer interface {
	Close() error
}

type ReadWriter interface {
	Reader
	Writer
}

type ReadCloser interface {
	Reader
	Closer
}

type WriteCloser interface {
	Writer
	Closer
}

  上面是标准 io 包里,我们常用的接口,可以看到 ReadWriter 接口是嵌入 Reader、Writer 接口组合而成的新接口,这样

我们就不用在重复的定义被嵌入接口的方法,直接通过嵌入就可以了。嵌入类型同样适用于结构体类型,看下面例子:

type user struct {
	name string
	email string
}

type admin struct {
	user
	level string
}

  嵌入后,被嵌入的类型称之为内部类型,新定义的类型称之为外部类型,这里 user 就是内部类型,而 admin 是外部类型

       通过嵌入类型,与内部类型相关的字段、方法、标识符等都会被外部类型所拥有,就像外部类型自己的一样,这样就达到了

代码快捷复用组合的目的

       同时,外部类型还可以添加自己的方法,字段等,可以很方便的扩展外部类型的功能

type user struct {
	name string
	email string
}

type admin struct {
	user
	level string
}

func main() {
	ad := admin{user{"张三","zhangsans@qq.com"},"管理员"}
	fmt.Println("可以直接调用,名字是:",ad.name)
	fmt.Println("也可以通过内部类型调用:",ad.user.name)
	fmt.Println("但新增的属性只能直接调用:",ad.level)
}

  上面是嵌入类型的使用,在初始化的时候,我们采用的是字面值的方式,先初始化 user 这个内部类型,再初始化

新增的 level 属性

        对于内部类型的属性和方法访问上,我们可以采用外部类型直接访问,也可以通过内部类型进行访问,但是我们为

外部类型新增方法属性字段,只能使用外部类型访问,因为内部类型没有这些

       当然,外部类型也可以声明同名的字段或方法,来覆盖内部类型,这种情况方法比较多,以方法为例:

type user struct {
	name string
	email string
}

type admin struct {
	user
	level string
}

func (u user) sayHello()  {
	fmt.Println("Hello,I am a user")
}

func (a admin) sayHello()  {
	fmt.Println("Hello,I am a admin")
}

func main() {
	ad := admin{user{"张三","zhangsans@qq.com"},"管理员"}
	ad.user.sayHello()
	ad.sayHello()
}

  内部类型 user 有一个 sayHello 方法,外部类型对其进行了覆盖,同名重写 sayHello,然后在 main 方法分别访问这两个

类型的方法,打印输出:

Hello,I am a user
Hello,I am a admin

    从上面的输出可以看出,方法 sayHello 被覆盖了

       嵌入类型还有一个强大的地方就是:如果内部类型实现了某个接口,那么外部类型也被认为实现了这个接口,如下示例:

type Hello interface {
	hello()
}

type user struct {
	name string
	email string
}

type admin struct {
	user
	level string
}

func (u user) hello() {
	fmt.Println("Hello, I am a user")
}

func sayHello(h Hello)  {
	h.hello()
}

func main() {
	ad := admin{user{"张三","zhangsans@qq.com"},"管理员"}
	sayHello(ad.user) // 使用 user 作为参数
	sayHello(ad)      // 使用 admin 作为参数
}

  新增一个 Hello 接口,然后让 user 类型实现这个接口,最后定义了一个 sayHello 方法,它接受一个 Hello 类型的

参数,最后我们在 main 函数调用的时候,发现不管是 user 类型吧,还是 admin 类型作为参数传递给 sayHello 都能正

常调用,这里就能说名 admin 接口实现了接口 Hello,但是又没有显示声明 admin 实现,所以这个实现是通过内部类型

user 实现的,因为 admin 包含了 user 所有方法和字段,所以也就实现了这个接口

原文地址:https://www.cnblogs.com/leeyongbard/p/10462645.html