继承的深入讨论
结构体可以使用嵌套匿名结构体所有的字段和方法
首字母大写或者小写的字段、方法,都可以使用。
type A struct {
Name string
age int
}
func (a *A) SayOk() {
fmt.Println("A SayOk", a.Name)
}
func (a *A) hello() {
fmt.Println("A hello", a.Name)
}
type B struct {
A
}
func main() {
var b B
b.A.Name = "tom"
b.A.age = 19
b.A.SayOk()
b.A.hello()
}
输出:
匿名结构体字段访问可以简化
type A struct {
Name string
age int
}
func (a *A) SayOk() {
fmt.Println("A SayOk", a.Name)
}
func (a *A) hello() {
fmt.Println("A hello", a.Name)
}
type B struct {
A
}
func main() {
b.Name = "smith"
b.age = 20
b.SayOk()
b.hello()
}
输出:
对上面的代码小结
当我们直接通过 b 访问字段或方法时,其执行流程如下比如 b.Name编译器会
先看 b 对应的类型有没有 Name, 如果有,则直接调用 B 类型的 Name 字段如果
没有就去看 B 中嵌入的匿名结构体 A 有没有声明 Name 字段,如果有就调用,如果没有继续查找..如果都找不到就报错.当结构体和匿名结构体有相同的字段或者方法时,编译器采用
就近访问原则访问
如希望访问匿名结构体的字段和方法,可以通
过匿名结构体名来区分
type A struct {
Name string
age int
}
func (a *A) SayOk() {
fmt.Println("A SayOk", a.Name)
}
func (a *A) hello() {
fmt.Println("A hello", a.Name)
}
type B struct {
A
Name string
}
func (b *B) SayOk() {
fmt.Println("B SayOk", b.Name)
}
func main() {
var b B
b.Name = "jack" // ok
b.A.Name = "scott"
b.age = 100 //ok
b.SayOk() // B SayOk jack
b.A.SayOk() // A SayOk scott
b.hello() // A hello ? "jack" 还是 "scott"
}
输出结果:
结构体嵌入两个(或多个)匿名结构体,如两个匿名结构体有相同的字段和方法(同时结构体本身没有同名的字段和方法),在访问时,就必须明确指定匿名结构体名字,否则编译报错。
type A struct {
Name string
age int
}
type B struct {
Name string
Score float64
}
type C struct {
A
B
//Name string
}
func main() {
var c C
-- 如果c 没有Name字段,而A 和 B有Name, 这时就必须通过指定匿名结构体名字来区分
-- 所以 c.Name 就会包编译错误, 这个规则对方法也是一样的!
c.A = "tom" -- error
c.A.Name = "tom" -- 正确
fmt.Println("c")
}
如果一个 struct
嵌套了一个有名结构体,这种模式就是
组合,如果是组合关系,那么在访问组合的结构体的字段或方法时,
必须带上结构体的名字
type A struct {
Name string
age int
}
type B struct {
Name string
Score float64
}
type D struct {
a A -- 有名结构体
}
func main() {
-- 如果D 中是一个有名结构体,则访问有名结构体的字段时,就必须带上有名结构体的名字
-- 比如 d.a.Name
var d D
d.a.Name = "jack"
}
嵌套匿名结构体后,也可以在创建结构体变量(实例)时,直接指定各个匿名结构体字段的值
type Goods struct {
Name string
Price float64
}
type Brand struct {
Name string
Address string
}
type TV struct {
Goods
Brand
}
func main() {
//嵌套匿名结构体后,也可以在创建结构体变量(实例)时,直接指定各个匿名结构体字段的值
tv := TV{ Goods{"电视机001", 5000.99}, Brand{"海尔", "山东"}, }
tv2 := TV{
Goods{
Price : 5000.99,
Name : "电视机002",
},
Brand{
Name : "夏普",
Address :"北京",
},
}
}
或者嵌套指针类型:
type Goods struct {
Name string
Price float64
}
type Brand struct {
Name string
Address string
}
type TV2 struct {
*Goods
*Brand
}
func main() {
fmt.Println("tv", tv)
fmt.Println("tv2", tv2)
tv3 := TV2{ &Goods{"电视机003", 7000.99}, &Brand{"创维", "河南"}, }
tv4 := TV2{
&Goods{
Name : "电视机004",
Price : 9000.99,
},
&Brand{
Name : "长虹",
Address : "四川",
},
}
}
结构体的匿名字段是基本数据类型,如何访问, 下面代码输出什么
type Monster struct {
Name string
Age int
}
type E struct {
Monster
int
n int
}
func main() {
//匿名字段时基本数据类型的使用
var e E
e.Name = "Tom"
e.Age = 300
e.int = 20
e.n = 40
fmt.Println("e=", e)
}
输出结果:
说明
如果一个结构体有 int 类型的匿名字段,就不能第二个。如果需要有多个 int 的字段,则必须给 int 字段指定名字
多重继承
多重继承说明
如一个 struct 嵌套了多个匿名结构体,那么该结构体可以直接访问嵌套的匿名结构体的字段和方法,从而实现了多重继承。
案例演示
多重继承细节说明
如嵌入的匿名结构体有相同的字段名或者方法名,则在访问时,需要通过匿名结构体类型名来区分。
为了保证代码的简洁性,建议大家尽量不使用多重继承