Golang中匿名结构体和匿名字段,结构体嵌套,模拟继承性学习


struct

今天主要记录 匿名结构体和匿名字段,结构体嵌套,模拟继承性

一.匿名结构体和匿名字段

1.匿名结构体

匿名结构体:即没有名字的结构体,在创建匿名结构体时,同时初始化结构体。
实例:

// 没有结构体命名过程, 直接创建一个结构体,并初始化
s2 := struct { 
 name string
 age  int
}{}

初始化时必须的, 不然会编译报错。实例中,我未具体初始化,使用了默认值。通常,这个语法在实际开发中使用较少,作为了解即可

2.匿名字段

匿名字段:一个结构体的字段没有字段名

我们定义一个Worker结构体,有两个匿名字段,:

type Worker struct {
 string //匿名字段
 int    
 //string  再次定义一个 string 匿名字段时编译报错
}

匿名字段,默认使用数据类型作为名字,那么匿名字段的类型就不能重复,否则会冲突。

.
bob := Worker{"Bob", 22}
fmt.Println(bob)
fmt.Println(bob.string)
fmt.Println(bob.int)

输出:

{Bob 22}
Bob
22

在实际开发中几乎没有人会这么写的,但是我们仍然有必要了解一下,为模拟继承性打好基础。

二.结构体嵌套

结构体嵌套:一个结构体可能包含一个字段,而这个字段反过来就是一个结构体,这种结构被称为嵌套结构。

has a

1.实例

定义图书, 学生结构体。其中,学生结构体嵌套了图书结构体

// 定义 Book 结构体
type Book struct {
 bookName string
 price float64
} 
// 定义 Student 结构体,其中一个字段是 Book 类型
type Student struct {
 name string
 age  int
 book Book  // 嵌套 Book 结构体 
}

初始化结构体:

// 声明初始化 book
book1 := Book{
 bookName:  "三国演义",
 price: 56.5,
}

// 声明初始化 sutdent
student1 := Student{
 name: "Tom",
 age:  20,
 book: book1,
}
fmt.Println("student1 结构体内容:", student1)
fmt.Printf("访问 book1 中的字段,书名:%s,价格:%.2f\n", student1.book.bookName, student1.book.price)

输出:

student1 结构体内容: {Tom 20 {三国演义 56.5}}
访问 book1 中的字段,书名:三国演义,价格:56.50
student1.bookName
student1.bookName

三.结构体模拟继承性

在学习了前两小节后,可以顺利的学习Golang中的继承,因为前两小节是学习继承的知识铺垫。

其实Golang并不是纯粹的面向对象的编程语言,但也可以实现继承关系,类似:

class_sub extend class_fatherclass_father(class_sub)
is a

1.实例

Golang中通过嵌套匿名结构体来实现继承,具体是什么样的呢?我们实例操作一下:

//1.定义父类
type Person struct {
 name string
 age  int
}

//2.定义子类
type Student struct {
 Person        //模拟继承结构
 school string //子类的新增属性
}
StudentPersonPerson

实例操作如下:

//1.创建父类的对象
p1 := Person{name: "张三", age: 30}
fmt.Println("父类对象:", p1)

//2.创建子类的对象
s1 := Student{Person{"李四", 17}, "清华大学"}
fmt.Println("子类对象 s1:", s1)

输出:

父类对象 p1: {张三 30}
子类对象 s1: {{李四 17} 清华大学}
student1.bookName
// 子类对象间接访问父类属性
s3.Person.name = "王五"
s3.Person.age = 19
s3.school = "清华大学"
fmt.Println("子类对象 s3:", s3)

// 子类对象直接访问父类属性
s3.name = "Ruby"
s3.age = 20
fmt.Println("子类对象 s3:", s3)

输出:

子类对象 s3: {{王五 19} 清华大学}
子类对象 s3: {{Ruby 20} 清华大学}

一般地,在实现了继承后,开发习惯通常都是直接子类对象.字段名来获取属性值。

但是如果有多重继承的情况,那就得指定访问哪个父类的属性。否则父类之间字段名重复的话,会引起访问歧义,编译会报错。

TeenageragePersonageStudent
// 新增一个青少年结构体,只有年龄属性
type Teenager struct {
 age int
}

// 学生结构体中多了一个 Teenager 匿名字段,模拟多重继承
type Student struct {
 Person
 Teenager // 新增了一个匿名字段,是Teenager结构体
 school string
}
TeenagerPersonageage

我们还是使用之前的直接访问属性的方式:

// 子类对象直接访问父类属性
s3.name = "Ruby"
s3.age = 16  // 重名的字段会报错
fmt.Println("子类对象 s3:", s3)

我们试着输出下报错信息:

# command-line-arguments
.\demo09_struct_extend.go:51:4: ambiguous selector s3.age  
ambiguous selector s3.ages3.agePersonTeenager
is ahas a
is a
type A struct{
 field
}

type B struct{
 A  // 匿名字段
}
has a
type C struct{
 field
}
type D struct{
 c C  // 聚合关系
} 

语法上的区别就是:嵌套的结构体是否匿名

结构体的记录暂时记录到这里,如果后续有新的知识,会持续更新。