断言及多态

本文介绍了Go语言中如何使用断言进行接口类型转换,详细阐述了类型断言的格式和接口之间无需强制类型转换的条件。同时,探讨了Go语言通过接口实现的多态特性,以动物、鸟和鱼为例,展示了多态在不同对象中具体表现形式的灵活性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

断言

package main

import "fmt"

// 定义一个通用接口:动物接口
type Animal interface {
	Breath()			// 动物都具备 呼吸方法
}

type Flyer interface {
	Fly()
}
type Swimer interface {
	Swim()
}

// 定义一个鸟类:其呼吸的方式是在陆地
type Bird struct {
	Name string
	Food string
	Kind string
}
func (b *Bird) Breath() {
	fmt.Println("鸟 在 陆地 呼吸")
}
func (b *Bird) Fly() {
	fmt.Printf("%s 在 飞\n", b.Name)
}

// 一定一个鱼类:其呼吸方式是在水下
type Fish struct {
	Name string
	Kind string
}
func (f *Fish) Breath() {
	fmt.Println("鱼 在 水下 呼吸")
}
func (f *Fish) Swim() {
	fmt.Printf("%s 在游泳\n", f.Name)
}

// 一个普通函数,参数是动物接口
func Display(a Animal) {
	// 直接调用接口中的方法
	a.Breath()
	// 调用实现类的成员:此时会报错
	fmt.Println(a.Name)
}

func main() {
	var b = &Bird{
		"斑鸠",
		"蚂蚱",
		"鸟类"
	}
	Display(b)
}

接口类型无法直接访问其具体实现类的成员(这是肯定的,要是让你访问其具体实现类成员那才有鬼了,因为在编译时,编译器只知道它是该接口类型,所以只让你访问该接口有的成员也就是所有方法,因为它能保证这些方法该接口的实现类一定有),需要使用断言(type assertions),对接口的类型进行判断(如果可以转型的,并进行转型并返回指定类型的实例),类型断言格式:

t := i.(T)			//不安全写法:如果i没有完全实现T接口的方法,这个语句将会触发宕机
t, ok := i.(T)		// 安全写法:如果接口未实现接口,将会把ok掷为false,t掷为T类型的0值
i代表接口变量
T代表转换的目标类型
t代表转换后的实例或变量

上述案例的Dsiplay就可以书写为:

func Display(a Animal) {
	// 直接调用接口中的方法
	a.Breath()
	// 调用实现类的成员:此时会报错
	instance, ok := a.(*Bird)	// 注意:这里必须是 *Bird类型,因为是*Bird实现了接口,不是Bird实现了接口
	if ok {
		// 得到了具体的实现类,才能访问实现类的导出成员
		fmt.Println("该鸟类的名字是:", instance.Name)
	} else {
		fmt.Println("该动物不是鸟类")
	}
}

接口类型转换

在接口定义时,其类型已经确定,因为接口的本质是方法签名的集合,如果两个接口的方法签名结合相同(顺序可以不同),则这2个接口之间不需要强制类型转换就可以相互赋值,因为go编译器在校验接口是否能赋值时,比较的是二者的方法集。

在上一节中,函数Display接收的是Animal接口类型,在断言后转换为了别的类型:*Bird(实现类指针类型):

func Display(a Animal) {
	instance, ok := a.(*Bird)		// 动物接口转换为了 *Bird实现类
	if ok {
		// 得到了具体的实现类,才能访问实现类的成员
		fmt.Println("该鸟类的名字是:", instance.Name)
	} else {
		fmt.Println("该动物不是鸟类")
	}
}
// 其实,断言还可以将接口转换成另外一个接口:

func Display(a Animal) {
	instance, ok := a.(Flyer)			// 动物接口转换为了飞翔接口
	if ok {
		instance.Fly()
	} else {
		fmt.Println("该动物不会飞")
	}

}

多态

多态是面向对象的三大特性之一,即一个类型具备多种具体的表现形式,在go中多态利用接口来实现,而不像Java依据继承和向上转型来实现

上述示例中,鸟和鱼都实现了动物接口的 Breath方法,即动物的Breath方法在鸟和鱼中具备不同的体现。我们在new出动物的具体对象实例时,这个对象实例也就实现了对应自己的接口方法。

// New出Animal的函数
func CreatAnimal(kind string) Animal{
	switch kind {
	case "鸟类":
		return &Bird{}
	case "鱼类":
		return &Fish{}
	default:
		return nil
	}

}

func main() {
	// 获取的是动物接口类型,但是实现类是鸟类
	 a1 := CreatAnimal("鸟类")
	a1.Breath()		// 鸟 在 陆地 呼吸

	// 获取的是动物接口类型,但是实现类是鱼类
	a2 := CreatAnimal("鱼类")
	a2.Breath()		// 鱼 在 水下 呼吸
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值