GO类型嵌套

来源:互联网 发布:建筑渲染软件 编辑:程序博客网 时间:2024/06/13 10:17

在GO结构体类型中嵌套一个其他的类型可以到达继承的目的。

语法:

struct {

T | *T

}

A field or method f of an anonymous field in a struct x is called promoted if x.f is a legal selector that denotes that field or method f.

Promoted fields act like ordinary fields of a struct except that they cannot be used as field names in composite literals of the struct.


Given a struct type S and a type named T, promoted methods are included in the method set of the struct as follows:

  • If S contains an anonymous field T, the method sets of S and *S both include promoted methods with receiver T. The method set of *S also includes promoted methods with receiver *T.
  • If S contains an anonymous field *T, the method sets of S and *S both include promoted methods with receiver T or *T.

example1:通过类型组合达到继承的目的
//main.go
package main
import "fmt"
type Father struct { //父类
    name string
    age  int
}
func (f Father) Speek(x string) { //父类Speek方法
    fmt.Println(x)
}
func (f *Father) Grow() { //父类Grow方法
    f.age += 1
}
type Child struct { //子类
    Father //类型组合
    height float32
}
func main() {
    var f = Father{name: "zlf", age: 30}
    var c = Child{Father: f, height: 170} //由于c.Father类型是值类型,所以将f赋值给c.Father时,会发生值拷贝过程
    c.Speek("Hello World")                //子类对象直接调用父类的Speek方法
    fmt.Println(c)
    c.Grow() //子类对象调用父类的Grow方法,但是Grow方法的接收器是c.Father,而不是c,更不是f
    fmt.Println("c = ", c)
    fmt.Println("f = ", f)
}
编译运行:

C:/go/bin/go.exe run test5.go [E:/project/go/proj/src/test]

Hello World

{{zlf 30} 170}

c = {{zlf 31} 170}

f = {zlf 30}

成功: 进程退出代码 0.

example2:嵌套类型Father,查看子类型Child的方法集

//main.go
package main
import "fmt"
type Father struct { //父类
    name string
    age  int
}
func (f Father) Speek(x string) { //父类Speek方法
    fmt.Println(x)
}
func (f Father) Grow() { //父类Grow方法
    f.age += 1
}
type Child struct { //子类
    Father //类型组合
    height float32
}
type SpeekGrower interface {
    Speek(x string)
    Grow()
}
func main() {
    var f = Father{name: "zlf", age: 30}
    var c = Child{Father: f, height: 170} //由于c.Father类型是值类型,所以将f赋值给c.Father时,会发生值拷贝过程
    var sg SpeekGrower
    sg = c  //类型CHILD
    sg.Speek("This is a test.")
    sg = &c  //类型*CHILD
    sg.Speek("This is a test.")
}
编译运行:

C:/go/bin/go.exe run test7.go [E:/project/go/proj/src/test]

This is a test.

This is a test.

成功: 进程退出代码 0.

//main.go
//main.go
package main
import "fmt"
type Father struct { //父类
    name string
    age  int
}
func (f Father) Speek(x string) { //父类Speek方法
    fmt.Println(x)
}
func (f *Father) Grow() { //父类Grow方法
    f.age += 1
}
type Child struct { //子类
    Father //类型组合
    height float32
}
type SpeekGrower interface {
    Speek(x string)
    Grow()
}
func main() {
    var f = Father{name: "zlf", age: 30}
    var c = Child{Father: f, height: 170} //由于c.Father类型是值类型,所以将f赋值给c.Father时,会发生值拷贝过程
    var sg SpeekGrower
    sg = c  //因为c类型是Child,值类型,赋值给接口时,会发生值拷贝,所以,该操作成功的前提是Child的所有方法都必须是值接收器
    sg.Speek("This is a test.")
    sg = &c
    sg.Speek("This is a test.")
}
编译运行:

C:/go/bin/go.exe run test7.go [E:/project/go/proj/src/test]

# command-line-arguments

.\test7.go:32: cannot use c (type Child) as type SpeekGrower in assignment:

Child does not implement SpeekGrower (Grow method has pointer receiver)

错误: 进程退出代码 2.


总结:通过上面两个例子,可以看出,当嵌套类型是Father时,类型Child的方法集只包括Father中接收器为值的方法;类型*Child的方法集包含了Father中所有的方法,所以*Child实现了上述的接口。


example3:嵌套类型*Father,查看子类型Child的方法集
//main.go
package main
import "fmt"
type Father struct { //父类
    name string
    age  int
}
func (f Father) Speek(x string) { //父类Speek方法
    fmt.Println(x)
}
func (f *Father) Grow() { //父类Grow方法
    f.age += 1
}
type Child struct { //子类
    *Father //类型组合
    height  float32
}
type SpeekGrower interface {
    Speek(x string)
    Grow()
}
func main() {
    var f = Father{name: "zlf", age: 30}
    var c = Child{Father: &f, height: 170}
    var sg SpeekGrower
    sg = c //类型Child,这里会发生值拷贝
    sg.Speek("This is a test.")
    sg = &c //类型*Child,这里会发生引用传递
    sg.Speek("This is a test.")
}
编译运行:

C:/go/bin/go.exe run test7.go [E:/project/go/proj/src/test]

This is a test.

This is a test.

成功: 进程退出代码 0.


OK,通过上面的案例可以看出,当内嵌类型是*Father时,类型Child和*Child都包含了Speek和Grow方法,所以实现了SpeekGrower接口。



0 0
原创粉丝点击