十. Go学习:接口详解

接口概念

Go语言提供了接口(interface)这类数据类型,其把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口。

Interface可以定义一组方法,而这些方法在interface(){}里是不需要实现的,且其中不能包含任何变量。在Go中的接口我们在外部实现时,只需一个变量含有接口类型中的所有方法,那么这个变量就实现了这个接口。与此同时,如果一个变量同时含有了多个interface类型的方法,那么这个变量就实现了多个接口。

需要我们注意的是,如果一个变量只含有一个interface的部分方法,那么这个变量就没有实现这个接口。

注:接口类似于C++中对象的概念,其是一个规范,不管底层怎么实现。比如车都有轮子、方向盘等,但宝马、比亚迪等不同牌子的车有不同的实现,但都遵循这个规范。

其重要意义是提供一种规范,类似于C++中的父类,但是实现多态无需使用virtual函数

代码实例

下面我们看一个代码实例

//Interface 类型可以定义一组方法,但是这些不需要实现。
//并且interface 不能包含任何变量。
package main

import (
	"fmt"
)

type Carer interface {
	GetName() string
	Run()
	DiDi()
}

//--------------------宝马
type BMW struct {
	Name string
}

func (p *BMW) GetName() string { //实现三个接口
	return p.Name
}
func (p *BMW) Run() {
	fmt.Printf("%s is running\n", p.Name)
}
func (p *BMW) DiDi() {
	fmt.Printf("%s is didi\n", p.Name)
}

//-------------------比亚迪
type BYD struct {
	Name string
}

func (p *BYD) GetName() string { //实现三个接口
	return p.Name
}
func (p *BYD) Run() {
	fmt.Printf("%s is running\n", p.Name)
}
func (p *BYD) DiDi() {
	fmt.Printf("%s is didi\n", p.Name)
}

func main() {
	var car Carer
	fmt.Println(car)
	var bmw BMW
	bmw.Name = "BMW"
	car = &bmw
	car.Run()
	var byd BYD
	byd.Name = "BYD"
	car = &byd
	car.Run()
}

  

如果我们少实现一个方法,我们会看到结果报错:missing DiDi method

代码如下:

package main

import (
	"fmt"
)

type Carer interface {
	GetName() string
	Run()
	DiDi()
}

//-------------------比亚迪
type BYD struct {
	Name string
}

func (p *BYD) GetName() string { //实现三个接口
	return p.Name
}
func (p *BYD) Run() {
	fmt.Printf("%s is running\n", p.Name)
}
//不实现DiDi()

func main() {
	var byd BYD
	byd.Name = "BYD"
	car = &byd
	car.Run()
}

Go语言包中的实例-自定义结构体调用Sort排序

Go语言中定义了一个Sort函数,其输入是一个接口,详情如下两图所示,这意味我们自定义的结构体,如果实现了这个接口中的方法,就能调用这个Sort进行排序。

代码如下:

package main

import (
	"fmt"
	"math/rand"
	"sort"
)

type Student struct {
	Name string
	Id   string
	Age  int
}
type StudentArray []Student //取别名

func (p StudentArray) Len() int {
	return len(p)
}
func (p StudentArray) Less(i, j int) bool {
	return p[i].Name > p[j].Name
}
func (p StudentArray) Swap(i, j int) {
	p[i], p[j] = p[j], p[i]
}

func main() {
	var stus StudentArray
	for i := 0; i < 10; i++ {
		stu := Student{
			Name: fmt.Sprintf("stu%d", rand.Intn(100)),
			Id:   fmt.Sprintf("110%d", rand.Intn(10)),
			Age:  rand.Intn(100),
		}
		stus = append(stus, stu)
	}
	for _, v := range stus {
		fmt.Println(v)
	}
	fmt.Println("\n")
	sort.Sort(stus)
	for _, v := range stus {
		fmt.Println(v)
	}
}

   

接口嵌套

代码实例:

package main

import (
	"fmt"
)

type Reader interface {
	Read()
}
type Writer interface {
	Write()
}
type ReadWriter interface {
	Reader
	Writer
}

func Test(rw ReadWriter) { //传入为接口
	rw.Read()
	rw.Write()
}
//用File类实现这个接口
type File struct {
}

func (f *File) Read() {
	fmt.Println("read data")
}
func (f *File) Write() {
	fmt.Println("write data")
}

func main() {
	var f *File
	var b interface{}
	b = f
	v, ok := b.(ReadWriter) //判断一个变量是否实现了指定接口
	fmt.Println(v, ok)
	//	Test(&f) //文件类实现了这个接口,就能用调用这个接口
}

类型断言

如下面代码所示,由于Test()传入的是一个接口,其并不知道到它是什么类型,如果我们没有a.(int)这个类型断言,就会报错。

package main

import (
	"fmt"
)

func Test(a interface{}) {
	b := a.(int)
	b += 3
	fmt.Println(b)
}
func main() {
	var b int
	Test(b)
}

对类型的判断代码:传入一个函数判断传入参数的类型

package main

import (
	"fmt"
)

type Student struct {
	Name string
	Sex  string
}

func Test(a interface{}) {
	b, ok := a.(Student)
	if ok == false {
		fmt.Println("convert failed")
		return
	}
	//	b += 3
	fmt.Println(b)
}
func just(items ...interface{}) {
	for index, v := range items {
		switch v.(type) {
		case bool:
			fmt.Println("%d params is bool, value is %v\n", index, v)
		case int, int64, int32:
			fmt.Println("%d params is int, value is %v\n", index, v)
		case float32, float64:
			fmt.Println("%d params is float, value is %v\n", index, v)
		case string:
			fmt.Printf("%d params is string, value is %v\n", index, v)
		case Student:
			fmt.Printf("%d params is student, value is %v\n", index, v)
		}
	}
}
func main() {

	var b Student = Student{
		Name: "stu01",
		Sex:  "female",
	}
	Test(b)
	just(28, 8.2, "this is a test")
}

  

空接口

interface{},接口中一个方法也没有,所以任何类型都实现了空接口,也就是任何变量都可以赋值给空接口。

接口应用范例:通用链表类

package main

import (
	"fmt"
)

type LinkNode struct {
	data interface{}
	next *LinkNode
}
type Link struct {
	head *LinkNode
	tail *LinkNode
}

func (p *Link) InsertTail(data interface{}) {
	node := &LinkNode{
		data: data,
		next: nil,
	}
	if p.tail == nil && p.head == nil {
		p.tail = node
		p.head = node
		return
	}
	p.tail.next = node
	p.tail = node
}
func (p *Link) Trans() {
	g := p.head
	for g != nil {
		fmt.Println(g.data)
		g = g.next
	}
}
func main() {
	var intLink Link
	for i := 0; i < 10; i++ {
		intLink.InsertTail(i)
	}
	intLink.Trans()
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值