第15节 Go中的继承

280 阅读3分钟
  • 继承可以让代码复用。比如当结构体中存在相同的属性和方法时,我们可以抽象出一个共用的父结构体,让其他子结构体继承该父结构体即可,这样子结构体就不需要再定义这些相同属性和方法了。
  • 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()
}
  • 运行结果:

image.png

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() image.png

  • 结构体匿名结构体相同的字段和方法时,编译器就近访问原则,如果希望访问匿名结构的字段和方法,可以通过匿名结构体名来区分
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)
}