golang结构体与接口嵌套关系

410 阅读2分钟

接口与结构体

type Person interface {
    Eat()
    Act()
}

type Student struct {
    Name string
}

type Teacher struct {
    Name string
}

// 学生实现接口函数
func (s *Student) Eat() {
    fmt.Printf("student %s eat\n", s.Name)
}
func (s *Student) Act() {
    fmt.Printf("student %s act study\n", s.Name)
}

// 老师实现接口函数
func (t *Teacher) Eat() {
    fmt.Printf("teacher %s eat\n", t.Name)
}
func (t *Teacher) Act() {
    fmt.Printf("teacher %s act teach\n", t.Name)
}

func main() {
    // 创建人类接口
    var person Person

    // 创建学生
    student := &Student{Name: "高启强"}
    // 创建老师
    teacher := &Teacher{Name: "安欣"}

    person = student
    person.Eat()
    person.Act()

    person = teacher
    person.Eat()
    person.Act()

    /*
        student 高启强 eat
        student 高启强 act study
        teacher 安欣 eat
        teacher 安欣 act teach
    */
}

  代码可以看出,定义一个接口类型Person和二个结构体类型Student、Teacher,创建实例赋值给接口变量。接口变量调用同一个方法调用的却是每个实例自己实现的方法。
  interface 让 golang 编码更灵活、易扩展,使得 Go 拥有了面向对象多态的特性。
  接口里面包含的都是方法,不带有属性。实现了该接口的任何对象都可以给对应的接口类型变量赋值。

结构体嵌套结构体

// 定义人类结构
type Person struct {
    Name string
}

// 创建人类的方法
func (p *Person) MyName() {
    fmt.Printf("person my name is [%s]\n", p.Name)
}

// 定义学生结构体
type Student struct {
    Person
}

type Teacher struct {
    Person
}

// 创建老师的方法
func (t *Teacher) MyName() {
    fmt.Printf("teacher my name is [%s]\n", t.Name)
}

func main() {
    person := Person{Name: "高启兰"}
    person.MyName()

    student := &Student{Person: person}
    student.MyName()

    teacher := &Teacher{Person: person}
    teacher.MyName()

    /*
	person my name is [高启兰]
	person my name is [高启兰]
	teacher my name is [高启兰]
    */
}

  父类Person衍生出Student与Teacher,子类继承了父类的属性与方法,方法可以直接调用,子类也可以重写父类方法。

结构体嵌套接口

type People interface {
    MyName()
}

// 定义人类结构
type Person struct {
    Name string
}

// 创建人类的方法
func (p *Person) MyName() {
    fmt.Printf("person my name is [%s]\n", p.Name)
}

// 定义学生结构体
type Student struct {
    People
}

type Teacher struct {
    People
    Name    string
    Subject string
}

// 创建老师的方法
func (t *Teacher) MyName() {
    fmt.Printf("teacher my name is [%s] teach [%s]\n", t.Name, t.Subject)
}

func main() {
    // 创建人类实例
    person := Person{Name: "高启兰"}
    person.MyName()

    // 创建学生实例,People接口用person初始化
    student := &Student{People: &person}
    student.MyName()

    // 创建老师实例,再将teacher实例赋值给接口
    teacher := &Teacher{Name: "黄瑶", Subject: "化学"}
    var people People = teacher
    people.MyName()

    /*
        person my name is [高启兰]
	person my name is [高启兰]
	teacher my name is [黄瑶] teach [化学]
    */
}

  Student实例里面接口用Person实例初始化,调用有接口方法为接口实例对象的MyName方法。该方法可以被Student重写,调用即为重写后的方法
  Teacher实例中接口不初始化即为nil,实现MyName方法之后可以将Teacher实例估值给People接口,调用MyName为Teacher自己实现的方法。

个人观点

  个人认为可以无视结构体内嵌套的接口,若需要用实现接口方法的实例初始化即可,不需要自己实现接口方法,可以再次赋值给接口。