golang - 接口

352 阅读3分钟

这是我参与8月更文挑战的第23天,活动详情查看:8月更文挑战

什么是接口

面向对象世界中的接口的一般定义是“接口定义对象的行为”。它表示让指定对象应该做什么。实现这种行为的方法(实现细节)是针对对象的。

在go中,接口说一组方法签名。当类型为接口中的所有方法提供定义时,它被称为实现接口。它与oop非常相似。接口制定了类型应该具有的方法,类型决定了如何实现这些方法。

它把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口

接口定义了一组方法,如果某个对象实现了某个接口的所有方法,则此对象就实现了该接口

接口的定义语法

定义接口:

// 定义接口
type interface_name interface {
    name1 [return_type]
    name2 [return_type]
    name3 [return_type]
    ...
    namen [return_type]
}

// 定义结构体
type struct_name struct {
    // variables
}

// 实现接口方法
func(struct_name_variable struct_name)name1()[return_type] {
    // 方法实现
}
...
func(struct_name_variable struct_name)namen()[return_type] {
    // 方法实现
}

示例代码:

package main

import "fmt"

type Phone interface {
    call()
}

type aFeiPhone struct {
    
}

func(afeiPhone aFeiPhone) call() {
    fmt.Println("i am afei, i can call you")
}

type Iphone struct {
}

func(iPhone Iphone) call() {
    fmt.Println("I am iPhone, i can call you")
}

func main() {
    var phone Phone
    phone = new(aFeiPhone)
    phone.call()
    
    phone = new (IPhone)
    phone.call()
}

运行结果:

i am afei, i can call you

I am iPhone, i can call you
  • interface可以被任意的对象实现
  • 一个对象可以实现任意多个interface
  • 任意的类型都实现了空interface(我们这样定义:interface{}),也就是包含0个method的interface

interface

package main

import "fmt"

type Human struct {
    name  string
    age   int
    phone string
}
type Student struct {
    Human  //匿名字段
    school string
    loan   float32
}
type Employee struct {
    Human   //匿名字段
    company string
    money   float32
} //Human实现Sayhi方法
func (h Human) SayHi() {
    fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
} //Human实现Sing方法
func (h Human) Sing(lyrics string) {
    fmt.Println("La la la la...", lyrics)
} //Employee重写Human的SayHi方法
func (e Employee) SayHi() {
    fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name,
        e.company, e.phone) //Yes you can split into 2 lines here.
}

// Interface Men被Human,Student和Employee实现
// 因为这三个类型都实现了这两个方法
type Men interface {
    SayHi()
    Sing(lyrics string)
}

func main() {
    mike := Student{Human{"Mike", 25, "222-222-XXX"}, "MIT", 0.00}
    paul := Student{Human{"Paul", 26, "111-222-XXX"}, "Harvard", 100}
    sam := Employee{Human{"Sam", 36, "444-222-XXX"}, "Golang Inc.", 1000}
    Tom := Employee{Human{"Sam", 36, "444-222-XXX"}, "Things Ltd.", 5000}
    //定义Men类型的变量i
    var i Men
    //i能存储Student
    i = mike
    fmt.Println("This is Mike, a Student:")
    i.SayHi()
    i.Sing("November rain")
    //i也能存储Employee
    i = Tom
    fmt.Println("This is Tom, an Employee:")
    i.SayHi()
    i.Sing("Born to be wild")
    //定义了slice Men
    fmt.Println("Let's use a slice of Men and see what happens")
    x := make([]Men, 3)
    //T这三个都是不同类型的元素,但是他们实现了interface同一个接口
    x[0], x[1], x[2] = paul, sam, mike
    for _, value := range x {
        value.SayHi()
    }
}

运行结果:

This is Mike, a Student:
    Hi, I am Mike you can call me on 222-222-XXX
    La la la la... November rain
    This is Tom, an Employee:
    Hi, I am Sam, I work at Things Ltd.. Call me on 444-222-XXX
    La la la la... Born to be wild
    Let's use a slice of Men and see what happens
    Hi, I am Paul you can call me on 111-222-XXX
    Hi, I am Sam, I work at Golang Inc.. Call me on 444-222-XXX
    Hi, I am Mike you can call me on 222-222-XXX

那么interface里面到底能存什么值呢?如果我们定义了一个interface的变量,那么这个变量里面可以存实现这个interface的任意类型的对象。例如上面例子中,我们定义了一个Men interface类型的变量m,那么m里面可以存Human、Student或者Employee值

当然,使用指针的方式,也是可以的

但是,接口对象不能调用实现对象的属性

interface函数参数

interface的变量可以持有任意实现该interface类型的对象,这给我们编写函数(包括method)提供了一些额外的思考,我们是不是可以通过定义interface参数,让函数接受各种类型的参数