Go语言-接口(interface)

接口的基本介绍

在go语言中,多态的特性主要是通过接口来实现。

interface可以定义一组方法,但是不能包含方法体。

interface中不可以包含任何变量。

在接口方法实现的时候,参数列表和返回值列表要保持完全一致。

接口体现了程序设计的高内聚低耦合思想。

Go语言中实现接口是基于方法的,而不是基于接口本身(方法只要包含了接口中的方法就实现了该接口)。因此go中的接口是隐式的,跟java是不同的。

接口是约定行为的集合,它定义了对象能做什么,而不关心具体是谁在做。

接口入门

接口定义的语法如下

type 接口名 interface{

        method1(参数列表)返回值列表

        method2(参数列表)返回值列表

}

首先需要定义一个接口,这个接口中包含若干个方法。

定义若干个结构体,结构体中实现了接口中的所有方法,则称为该结构体实现了某接口。

在后续的使用中,比如实现某函数或方法,该函数的参数为接口,那么实现了该接口的所有结构体都可以传给该函数,并且根据传入的结构体调用方法。

type Usb interface {
	Start()
	Stop()
}

type Phone struct{}

func (p Phone) Start() {
	fmt.Println("手机开始工作。。。")
}

func (p Phone) Stop() {
	fmt.Println("手机结束工作。。。")
}

type Computer struct{}

func (c Computer) Start() {
	fmt.Println("电脑开始工作---")
}
func (c Computer) Stop() {
	fmt.Println("电脑结束工作---")
}

func Working(usb Usb) {
	usb.Start()
	usb.Stop()
}

func main() {
	var c Computer
	var p Phone
	Working(c)
	Working(p)
}

输出为

电脑开始工作---
电脑结束工作---
手机开始工作。。。
手机结束工作。。。

接口的使用细节

1. 接口本身不能创建实例,但是可以指向一个实现了该接口的自定义类型。

type Usb interface {
	Start()
	Stop()
}

func main() {
	var u Usb
	u.Start()
	u.Stop()
}
不能编译通过。。。

以下这样是可以的,当然前提是Phone实现了Usb接口。

func main() {
	var p Phone
	var u Usb = p
	u.Start()
	u.Stop()
}

2. 接口中的所有方法都没有方法体。

3. 某个结构体需要实现一个接口中的所有方法,我们才说这个自定义类型实现了该接口。

4. 只要是自定义结构体,都可以实现接口,而不一定是结构体。

type integer int
这种也属于是自定义类型

5. 一个自定义类型可以实现多个接口。(实现的方法够多就覆盖多个借口了)

6. 如果A接口继承多个接口,这时如果某个自定义类型需要实现该接口,就必须将A接口中的所有方法都实现。

type BInterface interface{
    test1()
}
type CInterface interface{
    test2()
}
type AInterface interface{
    BInterface
    CInterface
    test3()
}

type Stu struct{
}

func (stu Stu) test1(){
}
func (stu Stu) test2(){
}
func (stu Stu) test3(){
}

该案例中,Stu结构体实现了A、B、C三个接口

7. interface类型默认是一个指针(引用类型),如果没有对interface进行初始化,那么会输出为nil。

8. 空接口interface{}没有任何方法,因此所有的方法都实现了该接口。可以将任何一个变量赋值给一个空接口。

9. 以下代码是错误的

type AInterface interface{
    test01()
    test02()
}

type BInterface interface{
    test01()
    test03()
}

type CInterface interface{
    AInterface
    BInterface
}

func main(){

}

CInterface接口继承了AInterface和BInterface,且AInterface和BInterface中包含两个同名函数test01(),报错。

10. 如果一个自定义类型实现接口的方法,接受参数是指针,那么只能将指针传给接口变量。

package main

import (
	"fmt"
)

type Usb interface {
	Say()
}

type Stu struct{
}

func (stu *Stu) Say(){
	fmt.Println("Say()")
}

func main(){
	var stu Stu
	var u Usb = stu  编译错误
	var u Usb = &stu  正确用法
	u.Say()
}

接口实践

自定义结构体实现了官方函数的接口,就可以调用系统官方函数。

package main

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

type Hero struct {
	Name string
	Age  int
}

type HeroSlice []Hero

func (hs HeroSlice) Len() int {
	return len(hs)
}
func (hs HeroSlice) Less(i, j int) bool {
	return hs[i].Age < hs[j].Age
}
func (hs HeroSlice) Swap(i, j int) {
	hs[i], hs[j] = hs[j], hs[i]
}
func main() {
	// 对一个结构体进行排序
	// 可以使用系统提供的方法
	var heroes HeroSlice
	for i := 0; i < 10; i++ {
		hero := Hero{
			Name: fmt.Sprintf("英雄%d", rand.Intn(100)),
			Age:  rand.Intn(100),
		}
		heroes = append(heroes, hero)
	}
	for _, v := range heroes {
		fmt.Println(v)
	}
	fmt.Println("--------------------")
	sort.Sort(heroes)

	for _, v := range heroes {
		fmt.Println(v)
	}
}

该例子中HeroSlice类型实现了sort.Interface(Len()函数、Less()函数、Swap()函数)

因此可以直接sort.Sort(heroes)这样进行使用。

接口和继承的比较

继承的价值在于:解决代码的复用性和可维护性。

接口的价值在于:设计(这个太抽象了)

扩展一下,接口的价值体现在以下三个方面:

1. 跨模块通信:类似于积木不同模块之间的拼接,需要一个接口连接。

比如:

  • 用户模块调用支付模块
  • 数据访问层调用业务逻辑层
  • 外部系统对接内部服务

2. 多态:统一处理多种不同类型。

对多个不同类型做相同操作,接口可以统一他们的行为。

3. 封装:对外隐藏实现细节。

你可能感兴趣的:(#,golang学习笔记,golang,开发语言,后端)