Golang学习笔记(二)interface

golang不像其他面向对象语言,语法上不支持类和继承等概念。而golang就是一个纯粹的面向接口编程的语言。今天就来走一遍golang的接口学习。

一、接口的定义

接口怎么定义呢?使用关键字interface

type 接口名 interface{}

就这么简单,一个接口就定义好了,但是这个接口,熟悉其他语言的人都应该知道,接口顾名思义就是拿来给别人用的东西,用什么呢?当然是用方法,所以里面还得有方法,这样才叫一个真正的接口。

type MyInterface interface {
	MyMethod() string
}

就这样,这就是一个有方法的接口了。由此,又可以给出接口的一个特性:接口是一组没有具体实现的方法集合

二、接口的实现

那都说了,它里面的方法是没有实现的,也就是说,接口定义好了,现在知道这接口里面能干啥,但是还没人干,那谁干呢?(这里就又一个衍生知识点 duck typing(鸭子类型),有兴趣的朋友,可以自行去深入了解一下)golang就比较民主,谁用谁去干(即谁用谁实现),这就跟java、c++等语言不一样了,接口定义好了,必须又一个实现类,那这个接口才算真正的接口。golang不是的,它比较自由。想用,就自己去实现。

package main

import "fmt"
// People接口
type People interface {
	ReturnName() string
}
// student"类"
type Student struct{
	Name string
}
// student实现了People的接口
func (s Student) ReturnName() string {
	return s.Name
}
// 使用接口
func UseInterfaceMethod(p People){
	result := p.ReturnName()
	fmt.Println(result)
}

func main() {
	var p People

	student := Student{Name:"海马"}
	
	p = student
	UseInterfaceMethod(p)
	// 结果为:海马
}

这里可以看到,Student实现了People中的方法(当然它里面也就只有一个方法,可以有多个,当全部被Student实现),我们就可以说这个Student实现了People这个接口,那么Student就可以理解为一个实现类,然后用这个接口的引用指向这个实现类的实例,那个就可以使用这个接口的方法了,但是结果肯定就只能是Student这个实现类的方法实现逻辑所产生的。

package main

import "fmt"
// People接口
type People interface {
	ReturnName() string
}
// student"类"
type Student struct{
	Name string
}
// human"类"
type Human struct{

}

// student实现了People的接口
func (s Student) ReturnName() string {
	return s.Name
}

// human实现了People的接口
func (h Human) ReturnName() string {
	return "Human result"
}

func UseInterfaceMethod(p People){
	name := p.ReturnName()
	fmt.Println(name)
}

func main() {
	var p People

	student := Student{Name:"海马"}
	p = student
	UseInterfaceMethod(p)
	// 结果为:海马
	human := Human{}
	p = human
	UseInterfaceMethod(p)
	// 结果为:Human result
}

由此可以看出,这个接口,我换用Human“类”实现了,方法逻辑是返回Human result。现在接口的引用重新指向了Human的实例,给到别人使用的时候,最后就变成了Human对方法实现的新逻辑产生的结果。所以说,golang就很灵活的实现了多态,接口引用还是那个引用,但是指向的不同实例(必须是实现了它的方法的实例),调用同一个方法,最终结果也不一样。

三、接口的特性

从上面的几个例子中可以看到,一个接口可以被任意对象实现,同样,一个接口也可以实现多个接口。
任意类型都实现了空interface(也就是包含0个method的interface),所以有时候可以把interface当作泛型来使用,一个方法的参数列表可以是interface,但是在方法内部使用的时候必须要做类型断言(即判断传进来的参数的类型是不是想要的),因为在golang中没有泛型的概念,并不会编译时绑定类型。而类型断言的方式有两种:Comma-ok断言和switch测试

package main

import (
	"fmt"
	"strconv"
)

// Human对象
type Human struct{
	name string
	age int
	phone string
}

// 通过定义interface参数,让函数接受各种类型的参数
// 通过这个Method(方法),Human对象实现了fmt.Stringer接口
// Stringer接口是fmt.Println()的参数,最终使得Human对象可以作为fmt.Println的参数被调用
func (h Human) String() string {
	return "<" + h.name + " - " + strconv.Itoa(h.age) + " years - phone " + h.phone + ">"
}

// 空接口
type Element interface{}

type List []Element

// 定义Person对象
type Person struct{
	name string
	age int
}

func (p Person) String() string {
	return "(name: " + p.name + " - age: " + strconv.Itoa(p.age) + " years)"
}

func main() {
	Lucy := Human{"Lucy", 29, "1866666666"}
	fmt.Println("This is a Human" , Lucy)

	list := make(List, 3)
	list[0] = 100
	list[1] = "This is a String"
	list[2] = Person{"HaiMa", 25}

	// Comma-ok断言 (实际开发中用得最多)
	for index, element := range list {
		// 判断变量的类型 格式:value, ok = element(T)
		// value是interface变量的值,ok是bool类型,element是interface的变量,T是断言的interface变量的类型
		if value, ok := element.(int); ok {
			fmt.Printf("list[%d] is an int and it's value is %d\n", index, value)
		} else if value, ok := element.(string); ok {
			fmt.Printf("list[%d] is an int and it's value is %s\n", index, value)
		}else if value, ok := element.(Person); ok {
			fmt.Printf("list[%d] is an int and it's value is %s\n", index, value.name)
		}else{
			fmt.Printf("list[%d] is a diffent type\n", index)
		}
	}
	// switch
	for index, element := range list {
		// 注意:element.(type)语法不能在switch外的任何逻辑中使用
		switch value := element.(type) {
		case int:
			fmt.Printf("list[%d] is an int and it's value is %d\n", index, value)
		case string:
			fmt.Printf("list[%d] is an int and it's value is %s\n", index, value)
		case Person:
			fmt.Printf("list[%d] is an int and it's value is %s\n", index, value.name)
		default:
			fmt.Printf("list[%d] is a diffent type\n", index)
		}
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值