一.基本介绍
interface类型可以定义一组方法,但是这些不需要实现。并且interface不能包含任何变量。到某个自定义类型(比如结构体Phone)要使用的时候,再根据具体情况把这些方法写出来。
二.基本语法
小结说明:
1.接口里的所有方法都没有方法体,即接口的方法都是没有实现的方法。接口体现了程序设计的多态和高内聚低耦合的思想。
2.Golang中的接口,不需要显式的实现。只要一个变量,含有接口类型中的所有方法,那么这个变量就实现这个接口。因此,Golang中没有implement这样的关键字
案例代码:
package main
import(
"fmt"
)
//声明定义一个接口
type Usb interface{
//声明了两个没有实现的方法
Start()
Stop()
}
type Phone struct{
}
//让iphone实现Usb接口的方法
func (p Phone) Start(){
fmt.Println("手机开始工作。。。。")
}
func (p Phone) Stop(){
fmt.Println("手机停止工作")
}
//相机
type Camer struct{
}
//让Camer 实现 Usb接口的方法
func (c Camer) Start(){
fmt.Println("相机开始工作。。。。")
}
func (c Camer) 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{}
camer := Camer{}
//关键点
computer.working(phone)
computer.working(camer)
}
接口的注意事项和细节:
1.接口本身不能创建实例,但是可以指向一个实现了该接口的自定义类型的变量(实例)
2.接口中所有的方法都没有方法体,即都没有实现的方法。
3.在Golang中,一个自定义类型需要将某个接听的所有方法都实现,我们说这个自定义类型实现了该接口。
4.一个自定义类型只有实现了某个接口,才能将该自定义类型的实例(变量)赋给接口类型。
5.只要是自定义数据类型,就可以实现接口,不仅仅是结构体类型。
6.一个自定义类型可以实现多个接口
7.Golang接口中不能有任何变量
8.一个接口(比如A接口)可以继承多个别的接口(比如B,C接口),这时如果要实现A接口,也必须将B,C接口的方法也全部实现
9.interface类型默认是另一个指针(引用类型),如果没有对interface初始化就使用,那么会输出nill
10.空接口interface{}没有任何方法,所以所有类型都实现了接口。
案例:
package main
import (
"fmt"
"math/rand"
"sort"
)
// 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
}
func (hs HeroSlice) Swap(i, j int) {
temp := hs[i]
hs[i] = hs[j]
hs[j] = temp
}
func main() {
//先定义一个数组/切片
var intSlice = []int{0, -1, 10, 7, 90}
//要求对intSlice切片进行排序
//1.冒泡排序
//2.也可以使用系统提供的方法
sort.Ints(intSlice)
fmt.Println(intSlice)
//对结构体切片进行排序
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)
}
//调用sort.Sort
sort.Sort(heroes)
fmt.Println("排序后")
for _, v := range heroes {
fmt.Println(v)
}
}
继承和接口的比较:
package main
import (
"fmt"
)
type Monkey struct {
Name string
}
type BirdAble interface {
Flying()
}
type FishAble interface {
Swimming()
}
func (this *Monkey) climbing() {
fmt.Println(this.Name, "爬树")
}
func (this *Monkey) Flyingg() {
fmt.Println(this.Name, "飞")
}
func (this *Monkey) Swimming() {
fmt.Println(this.Name, "游泳")
}
type LittleMonkey struct {
Monkey //继承
}
func main() {
Monkey := LittleMonkey{
Monkey{
Name: "悟空",
},
}
Monkey.climbing()
Monkey.Swimming()
Monkey.Flyingg()
}
代码小结:
1.当A结构体继承了B结构体,那么A结构体就自动的继承了B结构体的字段和方法,并且可以直接使用
2.当A结构体需要扩展功能,同时不希望去破坏继承关系,则可以去实现某个接口即可,因此我们可以认为:实现接口是对继承机制的补充
接口和继承的解决的问题不同:
继承的价值取决于:解决代码的复用性和可维护性。
接口的价值主要在于:设计,设计好各种规范(方法),让其它自定义类型去实现这些方法。
接口比继承更加灵活
接口比继承更加灵活,继承是满足is-a的关系,而接口只需要满足like - a的关系。
多态基本介绍
变量(实例)具有多种形态。面向对象的第三大特征,在Go语言,多态特征是通过接口实现的。可以按照统一的接口来调用不同的实现。这时接口变量就呈现不同的形态。
接口体现多态特征
1.多态参数
2.多态数组
类型断言
1.介绍
类型断言,由于接口是一般类型,不知道具体类型,如果要转成具体类型,就需要使用类型断言。
b = a.(Point)就是类型断言,表示判断a是否指向Point类型的变量,如果是就转成Point类型并赋给b变量,否则就报错