Go(Golang)_07_接口

接口

接口(多态):仅包含方法定义集合的数据类型(is-a类型)

1)接口是一种抽象类型;

2)实现接口代表:实现该接口类型的所有方法;


空接口:不包含任何方法的接口

1)Go中所有结构体类型均实现空接口;

2)空接口可以存储任意类型的数据(常用于函数参数)


接口类型的定义格式:

type  接口名  interface{
    方法1
    方法N
    其他接口
}

1)接口类型定义中的方法可仅指定方法名(不可指定程序段);

2)接口类型的定义中可包含其他已定义的接口(等同包含其方法);

//定义中方法和其他接口的出现顺序并无意义(也无需指定接收者)


接口变量定义的2种格式:声明后初始化、基于其他接口

(1)仅声明:var 接口变量名 接口类型

1)初始化:接口变量名 = 类型对象

2)若该类型对象的方法有指针接收者,则应使用&传递地址;

3)也可通过匿名结构体类型对象进行初始化(格式:结构体类型{值});

4)类型对象含有的方法但接口类型不含有,则接口变量不可调用该方法;

//非指针接收者在被调用时,编译器会隐式解引用


(2)接口变量名 := 其他接口

1)仅当一个接口被实现后,才可使用该接口定义其他接口;

2)被定义的接口可调用其他接口的所有方法(其他接口的别名);



接口变量定义后调用方法的格式:接口变量.方法(参数)

1)本质:通过初始化接口的结构体类型对象调用该方法;


如:定义接口和结构体类型,并实现该接口

1)编写程序;

package main

import (
    "fmt"
)

type People interface {
    Speak1(string) string
    Speak2(string) string
}

type Stduent struct{}

func (stu *Stduent) Speak1(think string) (talk string) {
    if think == "love" {
        talk = "You are a good boy"
    } else {
        talk = "hi"
    }
    return
}

func (stu Stduent) Speak2(think string) (talk string) {
    if think == "love" {
        talk = "You are a good boy"
    } else {
        talk = "hi"
    }
    return
}

func main() {
    // var peo1 People = Stduent{}   //该格式仅无指针接收者可使用
    //由于接口变量(基类)指向类型对象含有指针接收者,需使用&
    var peo2 People = &Stduent{}

    fmt.Println(peo2.Speak1("hi"), peo2.Speak2("love"))
}

2)运行结果;
在这里插入图片描述


值接收者方法和指针接收者方法名不可重复,原理如下:

1)编译器会自动复制值接收者创建相同的指针接收者方法

2)通过接口调用值接收者方法时,本质在调用编译器生成的指针接收者方法

//接口不能直接使用值接收者方法


接口值

接口值:由动态类型(结构体类型)和动态值(结构体类型对象)组成

1)接口零值(nil接口):动态类型和动态值均为nil(与空接口值不同);

2)通过nil接口调用任何方法都会让程序产生宕机;

3)动态类型不可比较,但动态值是可比较的;

//接口变量在未被初始化时,就属于接口零值


Go中所有类型分为两种:静态类型(Static Type)、动态类型(Dynamic Type)

1)静态类型:声明变量时指定的类型(且程序运行期间保持不变);

2)动态类型:由接口变量的值决定该接口变量的结构体类型;


接口值需注意事项:

1)一个接口值可指向任意多个动态值;

2)接口值之间可使用“==”和“!=”操作符比较;


如:通过两个实现接口的结构体定义接口变量,并调用方法

1)编写程序;

package main

import (
    "fmt"
)

type Animal interface {
    Eat()
}

type Cat struct {
    name string
}

func (c Cat) Eat() {
    fmt.Println(c.name, "Eat fish")
}

type Dog struct {
    name string
}

func (d Dog) Eat() {
    fmt.Println(d.name, "Eat bone")
}

func main() {
    var a1 Animal
    a1 = Cat{"mao"}
    fmt.Printf("%T\n", a1)
    a1.Eat()

    a2 := Dog{"Go"}
    a1 = a2
    fmt.Printf("%T\n", a1)
    a1.Eat()
}

2)运行结果;
在这里插入图片描述


类型断言

类型断言:判断接口变量的动态类型是否为指定的结构体类型或接口类型


类型断言格式:接口变量.(结构体类型或接口类型)

1)为结构体类型时,若匹配成功则返回该接口变量的动态值;

2)为接口类型时,若匹配成功则返回接口变量(但动态类型变为接口类型);

//匹配失败则返回nil


类型断言的返回值分:一个返回值,两个返回值

1)当仅有一个返回值时:仅返回true/false代表匹配是否成功;

2)当有两个返回值时:第一个返回动态类型,第二个返回true/false;

//第一种匹配失败会导致程序宕机(建议使用第二种)



类型断言方式分为:if语句(Comma-ok断言)、switch语句(类型分支)

(1)if语句,格式:

if 变量1, 变量2= 接口变量.(结构体类型或接口类型) {
	程序段
}

1)变量1一般为空白标识符“_”;


(2)switch语句,格式

switch  接口变量.type{
case  结构体类型1:
	程序段
case  结构体类型N:
	程序段
default:
	程序段
}

1)多个结构体类型可共用同一分支,使用“,”分隔;


如:通过类型断言决定程序的执行方式

1)编写程序;

package main

import (
    "fmt"
)

type Animal interface {
    Eat()
}

type Cat struct {
    name string
}

func (c Cat) Eat() {
    fmt.Println(c.name, "Eat fish")
}

type Dog struct {
    name string
}

func (d Dog) Eat() {
    fmt.Println(d.name, "Eat bone")
}

func Eat(a Animal) {
    _, ok := a.(Dog)
    if ok {
        fmt.Print("Dog is Eating,")
    }

    if _, ok := a.(Cat); ok {
        fmt.Print("Cat is Eating,")
    }

    a.Eat()
}

func main() {
    var a1 Animal
    a1 = Cat{"mao"}
    Eat(a1)

    a2 := Dog{"Go"}
    a1 = a2
    Eat(a1)
}

2)运行结果;
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值