Go语言中的接口

接口

接口的基本使用

Go语言中的接口很简单,通过interface就可以定义一个接口,在接口中定义的方法和java一样,是没有实现的,只做声明。接口的名字一般是方法名加er组成。不适合用er的,也可以用able结束。

type Flayer interface {
	fly()
}

如上我们定义了一个player的接口。Go语言中没有implements的关键字,如果要实现一个接口,参考下面的例子:

type bird struct {
}

// 按照接口中fly方法的返回值、参数列表做声明,函数的接受者定义为bird类型的一个指针,就相当于bird实现了Player接口
func (bi *bird) fly() {
	fmt.Println("bird fly...")
}

type plane struct {
}

func (bi *plane) fly() {
	fmt.Println("plane fly...")
}

func main() {
	flayer1 := new(bird)
	flayer1.fly()

	var flayer2 Flayer
	flayer2 = new(plane)
	flayer2.fly()
}

// 输出
bird fly...
plane fly...

接口类型的检测

因为接口是一个动态类型,就像上面的例子,有可能是bird类型,也有可能是plane类型。那么我们如何在运行时检测他到底是那种类型呢?代码如下:

func main() {
	var flayer2 Flayer
	flayer2 = new(plane)
	flayer2.fly()
	
    // ok是一个bool值 如果为true,则t是plane类型的值
	if t, ok := flayer2.(*plane); ok {
		fmt.Printf("%T", t)
	}
    
    if _, ok := flayer2.(*plane); ok {
		fmt.Printf("%T", t)
	}
    
}

// 输出:
bird fly...
plane fly...
*main.plane

除了上面的方式,也可以用type-switch的方式去做,代码如下:

switch t := flayer2.(type) {
case *plane:
    fmt.Printf("plane %T\n", t)
case *bird:
    fmt.Printf("bird %T\n", t)
default:
    fmt.Println("unknow")
}

如果我们不关注t的取值,那么上面的代码也可以简写成下面的样子:

switch flayer2.(type) {
case *plane:
    // todo
case *bird:
    // todo
default:
    // todo
}

空接口

在C语言中,有一个函数malloc函数用来开辟内存空间,参数是要开辟的空间大小,返回值是开辟出来的空间的地址。那么这个返回的地址是用来存什么类型的数据的呢?int类型,那返回值类型应该定义成int *p,float类型,那返回值类型应该定义成float *p。。。可是这个是确定不了的,是在用户使用的时候动态确定的,因此它的返回值类型不能是确定的,也应该是动态的。具体怎么表示呢?我们看看malloc函数的声明void *__cdecl malloc(size_t _Size);,他这里是用了void *类型的指针来指向一个空类型,一个不确定类型。在使用的时候我们可以将他强制转换成任意一个确定的类型。比如void * p1 = malloc(100); int p2 = (int *)p1

在java中,类似的功能是通过Object类来实现的,他是所有类型的基类,也就是说Object类的对象可以指向任意类型的一个引用。在Ts中,类似的写法是Any。那么在Go语言中,类似的功能则被叫做空接口。虽然换了一个概念,但是本质解决的问题是相同的。

Go语言中的空接口是接口类型的一种特殊形式,空接口没有任何方法,因此任何类型都无须实现空接口。换句话说,任何值都满足这个接口的需求,都可以看做实现了这个空接口。因此空接口类型可以保存任何值,也可以从空接口中取出原值。如下代码片段:

type Student struct {
	name  string
	age   int
	score float32
}

// 定义一个空接口
type Any interface{}

func main() {
	var val Any
	val = 1  // 将int类型赋值给空接口
	fmt.Printf("val has the value: %v\n", val)

	val = "go"  // 将string类型赋值给空接口
	fmt.Printf("val has the value: %v\n", val)

	stu := Student{"haxingyu", 12, 100.0}
	val = stu  // 将struct类型赋值给空接口
	fmt.Printf("val has the value: %v\n", val)

	switch t := val.(type) {
	case int:
		fmt.Printf("Type int %T\n", t)
	case string:
		fmt.Printf("Type int %T\n", t)
	case Student:
		fmt.Printf("Type int %T\n", t)
	default:
		fmt.Println("unknown")
	}
}

// 输出:
val has the value: 1
val has the value: go
val has the value: {haxingyu 12 100}
Type int main.Student
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

半__夏

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

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

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

打赏作者

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

抵扣说明:

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

余额充值