go 接口基础

go 接口基础

在面向对象的领域里,接口一般这样定义:接口定义一个对象的行为。接口只指定了对象应该做什么,至于如何实现这个行为(即实现细节),则由对象本身去确定。

在 Go 语言中,接口就是方法签名(Method Signature)的集合。当一个类型定义了接口中的所有方法,我们称它实现了该接口。这与面向对象编程(OOP)的说法很类似。接口指定了一个类型应该具有的方法,并由该类型决定如何实现这些方法

以python中鸭子类型为例: 类中如果有鸭子的走路的方法,鸭子说话的方法,无论你是什么类,你都是鸭子这种类型。

class Duck:   # 定义鸭子类型
    def speak(self):
        pass
        
    def run(self):
        pass
        
class Cat# 虽然没有继承Duck类,但是Cat就是Duck这一类型
    def speak(self):
        pass

    def run(self):
        pass	

通俗点说:不需要明面上的继承,只要你有Duck类中的方法,你就是Duck类的子类

在go语言中,也是有鸭子类型的概念,我们称之为接口(interface)

接口的定义

  • 接口实际上就是一种类型
// 定义接口  接口就是一系列方法的集合  但是没有实现 需要对象自己去实现
type Duck interface {
	speak(s string)
	run()
}

接口的实现与使用

func main() {
	tduck := TDuck{"唐老鸭1号", 4}
	tduck.speak("最呆的")    // 唐老鸭说: 我的名字是 唐老鸭1号 我是 最呆的
	tduck.run()				// 唐老鸭1号 走路歪歪扭扭

}


// 定义结构体
type TDuck struct {
	name string
	age int
}

type PDuck struct {
	name string
	age int
}
// 唐老鸭,实现speak和run
func (t TDuck) speak(s string)  {
	fmt.Println("唐老鸭说: 我的名字是 ", t.name, "我是", s)
}

func (t TDuck) run()  {
	fmt.Println(t.name,"走路歪歪扭扭")
}


// 普通鸭子,实现speak和run
func (t PDuck)speak(s string)  {
	fmt.Println("我是普通鸭子,我的名字是:",t.name,"我说:",s)
}
func (t PDuck)run()  {
	fmt.Println("我是普通鸭子,我的名字是:",t.name,"我走路歪歪扭扭")
}

在这里插入图片描述

需要注意的是,在go中接口的实现, 必须实现接口中所有的方法,才能出现上图中的标识,哪怕只有一个方法没有实现,都不算实现接口。
在这里插入图片描述

接口的实际用途

TDuck实现了Duck接口,所以TDuck的对象都是Duck类型的对象,可以赋值给Duck类型的对象,但是只能使用接口中的方法,不能使用具体类型的属性。

func main() {
	tduck := TDuck{"唐老鸭1号", 4}
	tduck.speak("最呆的")  // 唐老鸭说: 我的名字是 唐老鸭1号 我是 最呆的
	tduck.run()				// 唐老鸭1号 走路歪歪扭扭
	test5(tduck,"最呆的")  // 传参
    var duck Duck
    duck = tduck  // 直接赋值
}

func test5(d Duck, s string)  {
	d.run()  // 唐老鸭说: 我的名字是 唐老鸭1号 我是 最猛的
	d.speak(s)  // 唐老鸭1号 走路歪歪扭扭
}

空接口与匿名空接口

没有包含方法的接口称为空接口。空接口表示为 interface{}。由于空接口没有方法,因此所有类型都实现了空接口。

type Panada interface {}
func PrintPa(i Panada) {
	fmt.Printf("Type = %T, value = %v\n", i, i)
}

func main() {
	PrintPa(10)  // Type = int, value = 10
	PrintPa("lxx")   // Type = string, value = lxx
	PrintPa([3]int{1,2,3})  // Type = [3]int, value = [1 2 3]
}

匿名空接口,很简单就是没有名字的空接口,只使用一次,写法如下

func PrintPa(i interface {}) {
	fmt.Printf("Type = %T, value = %v\n", i, i)
}

类型断言

类型断言用于提取接口的底层值,在语法 i.(T) 中,接口 i 的具体类型是 T,该语法用于获得接口的底层值。用于解决在函数中,需要用到实现该接口的结构体对象的属性时使用。代码如下

func main() {
	tduck := TDuck{"唐老鸭1号", 4}
	test5(tduck,"最呆的")
}

func test5(d Duck, s string)  {
	d.run()
	d.speak(s)
	// 接口对象只有方法,没有具体类型(tduck)的属性
	//fmt.Println(d.name)   // 报错
	v,ok := d.(TDuck)   
    // ok 为 true时,断言成功,为false时断言失败
    // 也可以采用  v := d.(TDuck) 写法,但这种写法一但断言失败就会抛异常,不建议使用
	if ok {
		fmt.Println(v.name)  // 唐老鸭1号
		fmt.Println(v.age)   // 4
	}
}

类型选择

类型选择用于将接口的具体类型与很多 case 语句所指定的类型进行比较。它与一般的 switch 语句类似。唯一的区别在于类型选择指定的是类型,而一般的 switch 指定的是值。

类型选择的语法类似于类型断言。类型断言的语法是 i.(T),而对于类型选择,类型 T 由关键字 type 代替。

func main() {
	tduck := TDuck{"唐老鸭1号", 4}
	pduck := PDuck{"老鸭1号", 4}
	test6(tduck, "最呆的")
	test6(pduck, "最蒙的")

}

func test6(d Duck, s string) {
	switch obj := d.(type) {
	case TDuck:
		obj.run()
		fmt.Println(obj.name)
	case PDuck:
		obj.speak(s)
		fmt.Println(obj.age)
	}
}

补充:

  1. 接口的零值是 nil 所以接口是引用类型
  2. 接口的底层实现是通过指针指向了具体的类型(type : value)type 是接口底层的具体类型(Concrete Type),而 value 是具体类型的值。
var duck Duck
fmt.Println(duck)   // <nil>
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

go&Python

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值