- 继承可以让代码复用。比如当结构体中存在相同的属性和方法时,我们可以抽象出一个共用的父结构体,让其他子结构体继承该父结构体即可,这样子结构体就不需要再定义这些相同属性和方法了。
- golang 中如何实现继承?
如果一个struct中嵌套了另外一个匿名结构体,那么这个结构体可以直接访问匿名结构体的字段和方法,从而实现继承特性
// 动物
type Animal struct {
Age int
}
// 狗
type Dog struct {
Animal // 这就是嵌套的匿名结构体
Species string
}
1. 代码演示如何使用继承特性
package main
import "fmt"
// 学生
type Student struct {
Name string
Age int
Score int
}
// 共用方法
func (stu *Student) GetStudentInfo() {
fmt.Printf("学生名=%v 年龄=%v 成绩=%v\n", stu.Name, stu.Age, stu.Score)
}
// 共用方法
func (stu *Student) SetScore(score int) {
stu.Score = score
}
//******************************************************//
// 高中生
type HighSchoolStudent struct {
// 嵌入学生 Student 匿名结构体
Student
}
// 高中生独有的方法
func (h *HighSchoolStudent) getInfo() {
fmt.Println("我是高中生...")
}
// 大学生
type CollegeStudent struct {
// 嵌入学生 Student 匿名结构体
Student
}
// 大学生独有的方法
func (c *CollegeStudent) getInfo() {
fmt.Println("我是高中生...")
}
//******************************************************//
func main() {
var highSchoolStudent = &HighSchoolStudent{}
highSchoolStudent.Student.Name = "Kate"
highSchoolStudent.Student.Age = 20
highSchoolStudent.getInfo()
// 调用共用方法
highSchoolStudent.Student.SetScore(98)
fmt.Println("高中生=", *highSchoolStudent)
fmt.Println("~~~~~~~~~~~~~~~~~~~~~~")
var collegeStudent = &CollegeStudent{}
collegeStudent.Student.Name = "Jack"
collegeStudent.Student.Age = 16
collegeStudent.getInfo()
// 调用共用方法
collegeStudent.Student.SetScore(100)
fmt.Println("大学生=", *collegeStudent)
// 调用共用方法
collegeStudent.Student.GetStudentInfo()
}
- 运行结果:
2. 继承使用细节
- 结构体可以使用父结构体中所有属性和方法,不论该属性和方法的首字母大写或者小写都可以
- 匿名结构体字段和方法访问可以简化
package main
import "fmt"
type A struct {
Name string
age int
}
func (a *A) Get() {
fmt.Println("Get method !!!", a.Name)
}
func (a *A) hello() {
fmt.Println("hello method !!!", a.Name)
}
type B struct {
A
}
func main() {
var b B
b.A.Name = "Kate"
b.A.age = 22
b.A.Get()
b.A.hello()
// 简写👆🏻的代码
b.Name = "Jack"
b.age = 38
b.Get()
b.hello()
}
例如:b.A.Name 、b.A.hello() 可以简写成 b.Name、b.hello()
- 当结构体和匿名结构体有相同的字段和方法时,编译器就近访问原则,如果希望访问匿名结构的字段和方法,可以通过匿名结构体名来区分
package main
import "fmt"
type A struct {
name string
}
func (a *A) Get() {
fmt.Println("A Get method !!!", a.name)
}
type B struct {
A
name string
}
func (b *B) Get() {
fmt.Println("B Get method !!!", b.name)
}
func main() {
var b B
// 访问的A结构体的字段和方法
b.A.name = "Jack"
b.A.Get()
// 就近原则,则访问的是B结构体的字段和方法
b.name = "B Name"
b.Get()
}
- 当结构体中嵌入多个匿名结构体时,如果匿名结构体有相同字段和方法,但结构体本身没有和它们同命的字段和方法。此时访问时必须指明匿名结构体的名字,否则编译报错;总之实际开发中建议都带上匿名结构体的名称*
package main
import "fmt"
type A struct {
name string
}
type B struct {
name string
}
type C struct {
A
// 嵌套了一个名称的结构体
b B
name string
}
func main() {
var c C
c.A.name = "A Name"
// 访问结构体时要带上名字 b
c.b.name = "B Name"
c.name = "C name"
fmt.Println(c)
}
- 嵌套匿名结构体后,也可以在创建结构体变量时,直接指定各个匿名结构体字段值
package main
import "fmt"
type Product struct {
Name string
}
type Address struct {
Mobile string
}
type Order struct {
p Product
address *Address
}
func main() {
p := Product{"电脑"}
a := &Address{"15023765678"}
order := Order{p, a}
// order={{电脑} 0xc000010250},address={15023765678}
fmt.Printf("order=%v,address=%v\n",order, *order.address)
}