接口实现多态
[TOC]
😶🌫️go语言官方编程指南:https://pkg.go.dev/std
go语言的官方文档学习笔记很全,推荐去官网学习
😶🌫️我的学习笔记:github: https://github.com/3293172751/golang-rearn
区块链技术(也称之为分布式账本技术),是一种互联网数据库技术,其特点是去中心化,公开透明,让每一个人均可参与的数据库记录。
❤️💕💕关于区块链技术,可以关注我,共同学习更多的区块链技术。博客http://nsddd.top
接口(interface)
接口注意:
Golang中的接口也是一种数据类型,不需要显示实现。只需要一个变量含有接口类型中的所有方法,那么这个变量就实现了这个接口。
接口是一种规范,使用接口必须要按照它的规范来。
可以想象usb是现实中的接口,同时usb可以作为多种不同的尺寸和排线,这种设计需求在golang中也是大量存在的
按照循序应该是多态,但是在讲解多态之前需要讲解接口,因为在Golang中,多态的特性主要是通过接口来体现出来的
接口快速入门
接口💡简单的一个案例如下:
快速了解接口:
package main
import (
"fmt"
)
//声明/定义一个接口
type Usb interface {
//声明了两个没有实现的方法
Start()
Stop()
}
//声明/定义一个接口
type Usb2 interface {
//声明了两个没有实现的方法
Start()
Stop()
Test()
}
//定义手机的结构体
type Phone struct {
}
//让Phone 实现 Usb接口的方法
func (p Phone) Start() {
fmt.Println("手机开始工作。。。")
}
func (p Phone) Stop() {
fmt.Println("手机停止工作。。。")
}
type Camera struct {
}
//让Camera 实现 Usb接口的方法
func (c Camera) Start() {
fmt.Println("相机开始工作~~~。。。")
}
func (c Camera) Stop() {
fmt.Println("相机停止工作。。。")
}
//计算机
type Computer struct {
}
//编写一个方法Working 方法,接收一个Usb接口类型变量
//只要是实现了 Usb接口 (所谓实现Usb接口,就是指实现了 Usb接口声明所有方法)
func (c Computer) Working(usb Usb) {
//通过usb接口变量来调用Start和Stop方法
usb.Start()
usb.Stop()
}
func main() {
//测试
//先创建结构体变量
computer := Computer{}
phone := Phone{}
camera := Camera{}
//关键点
computer.Working(phone)
computer.Working(camera) //实现camera
}
🚀 编译结果如下:
[Running] go run "d:\文档\最近的\awesome-golang\docs\code\go-super\26-main.go"
手机开始工作。。。
手机停止工作。。。
相机开始工作~~~。。。
相机停止工作。。。
在文档里面接口的文档也是非常多的
接口概念
接口定义
接口类型可以定义一组方法,但是这些不需要实现,而且Interface
不能包含任何的变量
Go 语言提供了另外一种数据类型即接口,它把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口。把所有方法全部实现了,叫做实现了接口
💡简单的一个案例如下:
/* 定义接口 */
type interface_name interface {
method_name1 [return_type]
method_name2 [return_type]
method_name3 [return_type]
...
method_namen [return_type]
}
/* 定义结构体 */
type struct_name struct {
/* variables */
}
/* 实现接口方法 */
func (struct_name_variable struct_name) method_name1() [return_type] {
/* 方法实现 */
}
...
func (struct_name_variable struct_name) method_namen() [return_type] {
/* 方法实现*/
}
小结说明:
接口中所有的方法都没有方法体,即接口的方法都是没有实现的方法。接口体现了程序设计的多态和高内聚低耦合的思想
Golang中不需要显式存在,只要一个变量,含有接口类型中的所有方法,那么叫做这个变量实现了这个接口,
接口本身不能创建实例,但是它可以指向一个实现了该接口的自定义类型的变量
一个自定义类型可以实现多个接口
type BInterface interface{
Say()
}
type AInterface interface{
Hello()
}
type Monster struct{
//想让接口体monster即实现B接口也实现A接口
}
func (m monstall) Hello(){
fmt.Println("monstall hello()~~")
}
func (m monstall) Say(){
fmt.Println("monstall say()~~")
}
此时此刻monstall实现了Ainterface and Binterface
func main(){
var monster Monster
var Atow AInterface = monster
var Btow AInterface = monster
Atow.Say()
Btow.Hello()
}
Golang接口中不可以有任何的变量
type AInterface interface{
int //报错
Hello()
}
空接口
空接口表示没有任何约束,任何类型都可以实现空接口
⚡ 所有有时候需要任何类型的可以选择空接口~
//空接口表示任意类型
func main() {
var a interface{}
a = 20
a = "你好hello"
a = true
}
map定义空接口:
var m1 = make(map[string]interface{})
m1["username"] = userinfo["username"]
m1["password"] = userinfo["password"]
m1["age"] = userinfo["age"]
m1["hobby"] = 123
fmt.Println("m1=", m1)
fmt.Printf("userinfo[\"username\"] = %T", userinfo["username"])
切片定义空接口:
var slice1 = []interface{}{1, 2, 3, 4, 5, "hello", true}
fmt.Printf("a type is %T, a value is %v\n", slice1, slice1)
//a type is []interface {}, a value is [1 2 3 4 5 hello true]
空接口的一些实现
⚡ 空接口有一些实现的方案:
/*
* @Description: null interface
* @Author: xiongxinwei 3293172751nss@gmail.com
* @Date: 2022-10-04 21:37:41
* @LastEditTime: 2022-10-25 09:11:10
* @FilePath: \code\go-super\27-main.go
* @Github_Address: https://github.com/3293172751/cs-awesome-Block_Chain
* Copyright (c) 2022 by xiongxinwei 3293172751nss@gmail.com, All Rights Reserved. @blog: http://nsddd.top
*/
package main
import "fmt"
//空接口
type A interface{}
func show(a interface{}) {
fmt.Printf("type:%T value:%v", a, a) //type:interface {} value:100
}
func main() {
var a A
b := "hello"
a = b //表示a可以接收任意类型的数据
fmt.Println("a=", a) //a= hello
var num = 20
a = num //表示空接口可以接收任意类型的数值
fmt.Printf("a type is %T, a value is %v\n", a, a)
var stu = struct {
name string
age int
}{
name: "tom",
age: 20,
}
a = stu
fmt.Printf("a type is %T, a value is %v\n", a, a) //a type is struct { name string; age int }, a value is {tom 20}
show(100) //type:int value:100
//fmt.Println("a.name=", a.name) //空接口没有字段,不能直接访问字段"
}
🚀 编译结果如下:
[Running] go run "d:\文档\最近的\awesome-golang\docs\code\go-super\27-main.go"
a= hello
a type is int, a value is 20
a type is struct { name string; age int }, a value is {tom 20}
type:int value:100
接口之间也可以有继承的关系(比如AInterface可以继承BInterface and CInterface)
/*************************************************************************
> File Name: Interface.go
> Author: smile
> Mail: 3293172751nss@gmail.com
> Created Time: Sat 05 Mar 2022 01:36:23 PM CST
************************************************************************/
package main
import (
"fmt"
)
type BInterface interface {
test01() //定义test01一个方法
}
type CInterface interface {
test02()
}
type AInterface interface {
//at AInterface comprise BInterface and CInterface and it has its own way test03
BInterface
CInterface
test03() //意味着如果要实现Ainterface 就要实现下面的所有方法
}
//如果需要实现AInterface,就需要将BInterface CInterface的方法都实现
type Stu struct {
}
func (stu Stu) test01() {
}
func (stu Stu) test02() {
}
func (stu Stu) test03() {
}
//只有将三个方法全部实现了,那么stu就实现了AInterface 缺一不可!!!!!!!!
type T interface{
}
func main() {
var stu Stu
var a AInterface = stu
a.test01()
var t T = stu //ok
fmt.Println(t)
var t2 interface{} = stu
var num1 float64 = 8.8
t2 = num1
t = num1
fmt.Println(t2, t)
}
接口是引用类型~,传值的时候是以引用方式(地址)传送进去的
空接口interface{}没有任何的方法,所有的类型都实现了空接口,我们可以把任何的变量赋值给空接口
type T interface{
}
func main() {
var t T = stu //ok
fmt.Println(t)
//也可以这样写:
var t2 interface{} = stu
var num1 float64 = 8.8
t2 = num1 //可以直接将num1赋值
t = num1
fmt.Println(t2, t)
}
编译:
[root@mail golang]# go build -o Interface Interface.go
[root@mail golang]# ./Interface
{}
8.8 8.8
注意继承的时候,接口之间不可以有相同的方法名
type BInterface interface {
test01() //定义test01一个方法
test02()
}
type CInterface interface {
test02()
test03()
} /*---正常编译---*/
type AInterface interface {
AInterface
BInterface
} /*---编译错误---*/
func main(){
/*--报错:重复定义--*/
}
接口实践
常见报错,接口是属于引用传递
package main
import "fmt"
type Usb interface {
Say()
}
type Stu struct {
}
func (this *Stu) Say() {
fmt.Println("Say()")
}
func main() {
var stu Stu = Stu{}
// 错误! 会报 Stu类型没有实现Usb接口 ,
// 如果希望通过编译, var u Usb = &stu
var u Usb = stu
u.Say()
fmt.Println("here", u)
}
接口实现对Hero结构体切片的排序
实现对Hero结构体切片的排序
思想:使用冒泡排序也可以使用系统提供的方法
💡简单的一个案例如下:
package main
import (
"fmt"
"sort" //使用系统的方法
"math/rand"
)
//1.声明Hero结构体
type Hero struct{
Name string
Age int
}
//2.声明一个Hero结构体切片类型
type HeroSlice []Hero
//3.实现Interface 接口
func (hs HeroSlice) Len() int {
return len(hs)
}
//Less方法就是决定你使用什么标准进行排序
//1. 按Hero的年龄从小到大排序!!
func (hs HeroSlice) Less(i, j int) bool {
return hs[i].Age < hs[j].Age
//修改成对Name排序
//return hs[i].Name < hs[j].Name
}
func (hs HeroSlice) Swap(i, j int) {
//交换
// temp := hs[i]
// hs[i] = hs[j]
// hs[j] = temp
//下面的一句话等价于三句话
hs[i], hs[j] = hs[j], hs[i]
}
//1.声明Student结构体
type Student struct{
Name string
Age int
Score float64
}
//将Student的切片,安Score从大到小排序!!
func main() {
//先定义一个数组/切片
var intSlice = []int{0, -1, 10, 7, 90}
//要求对 intSlice切片进行排序
//1. 冒泡排序...
//2. 也可以使用系统提供的方法
sort.Ints(intSlice)
fmt.Println(intSlice)
//请大家对结构体切片进行排序
//1. 冒泡排序...
//2. 也可以使用系统提供的方法
//测试看看我们是否可以对结构体切片进行排序
var heroes HeroSlice
for i := 0; i < 10 ; i++ {
hero := Hero{
Name : fmt.Sprintf("英雄|%d", rand.Intn(100)),
Age : rand.Intn(100),
}
//将 hero append到 heroes切片
heroes = append(heroes, hero)
}
//看看排序前的顺序
for _ , v := range heroes {
fmt.Println(v)
}
//调用sort.Sort
sort.Sort(heroes)
fmt.Println("-----------排序后------------")
//看看排序后的顺序
for _ , v := range heroes {
fmt.Println(v)
}
i := 10
j := 20
i, j = j, i
fmt.Println("i=", i, "j=", j) // i=20 j = 10
}
接口VS继承
举例
如何理解继承和接口?
猴子如果学猴子,那就是继承,如果猴子想学鸟飞,学鱼游,就是接口
接口相当于是对继承的补充
package main
import(
"fmt"
)
type Monkey struct{
Name string
}
func (this *Monkey) climbing(){
fmt.Println(this.Name,"生来会爬树..")
}
//Little Monkey结构体
type LittleMonkey struct{
Monkey //匿名结构体
//继承
}
func main(){
//创建一个littleMonkey 实例
monkey := LittleMonkey{
Monkey{
Name : "悟空",
},
}
monkey.climbing()
}
[root@mail ~]# go run monkey.go
悟空 生来会爬树..
*如果猴子想学飞????☆: .。. o(≧▽≦)o .。.:*☆ **
//声明接口
type BirdAble interface{
Flying()
}
type BirdAble interfacpackage main
import (
"fmt"
)
//Monkey结构体
type Monkey struct {
Name string
}
//声明接口
type BirdAble interface {
Flying()
}
type FishAble interface {
Swimming()
}
func (this *Monkey) climbing() {
fmt.Println(this.Name, " 生来会爬树..")
}
//LittleMonkey结构体
type LittleMonkey struct {
Monkey //继承
}
//让LittleMonkey实现BirdAble
func (this *LittleMonkey) Flying() {
fmt.Println(this.Name, " 通过学习,会飞翔...")
}
//让LittleMonkey实现FishAble
func (this *LittleMonkey) Swimming() {
fmt.Println(this.Name, " 通过学习,会游泳..")
}
func main() {
//创建一个LittleMonkey 实例
monkey := LittleMonkey{
Monkey {
Name : "悟空",
},
}
monkey.climbing()
monkey.Flying()
monkey.Swimming()
}e{
Flying()
}
type Monkey struct{
Name string
}
func (this *Monkey) climbing(){
fmt.Println(this.Name,"生来会爬树..")
}
func (this *LittleMonkey) Swimming(){
fmt.Println(this.Name,"通过学习会游泳..")
}
//Little Monkey结构体
type LittleMonkey struct{
Monkey //匿名结构体
//继承
}
func main(){
//创建一个littleMonkey 实例
monkey := LittleMonkey{
Monkey{
Name : "悟空",
},
}
monkey.climbing()
monkey.Swimming()
}
实现接口可以看作是对继承的一种补充
接口和继承解决的问题不同
继承的主要价值在于:解决问题的复用性和可维护性
接口的主要价值在于:设计,设计好各种规范(方法),让其他自定义类型去是实现这些方法
接口比继承更加灵活
接口是比继承更加灵活的
继承是满足is - a的关系,而接口只需要满足like - a的关系
提示
接口在一定程度上实现代码解耦
END 链接
✴️版权声明 © :本书所有内容遵循CC-BY-SA 3.0协议(署名-相同方式共享)©