接口的最佳实现:
构建了结构体student还有自定义类型StudentSlice运用StudentSlice来实现接口sort.Sort,也就是三个函数:Len(),Less(i, j int)、Swap(i , j int)
代码实现:
package main
import (
"fmt"
"math/rand"
"time"
"sort"
)
//引用时间种子
type student struct{
name string
age int
scores int
}
type StudentSlice []student
func (stu StudentSlice) Len() int{
return len(stu)
}
func (stu StudentSlice) Less(i,j int)bool{
return stu[i].scores > stu[j].scores
}
func (stu StudentSlice) Swap(i,j int){
stu[i],stu[j] = stu[j],stu[i]
}
type Heroes struct{
name string
age int
}
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]
//进行交换
}
//完成了这三个函数那么就说这样实现了这个接口
type HeroSlice []Heroes
//自定义的类型
func main() {
rand.Seed(time.Now().UnixNano()) //引入一个时间种子
//引一个时间种子,这样生成的随机数就不是伪随机数
var heroslice HeroSlice //HeroSlice已经实现了这一个接口
for i := 0; i < 11; i++ {
hero := Heroes{
name: fmt.Sprintf("英雄%d", rand.Intn(100)+59),
age: rand.Intn(5369) + 59,
}
heroslice = append(heroslice, hero)
}
for _, v := range heroslice {
fmt.Printf("编号 : %v ,age : %d\n", v.name, v.age)
}
sort.Sort(heroslice)
fmt.Println("排序后····")
for _, v := range heroslice {
fmt.Printf("编号 : %v ,age : %d\n", v.name, v.age)
}
//输出的是根据年龄的大小来排序的从小到大
/* rand.Seed(time.Now().UnixNano())
fmt.Println("n",rand.Intn(100)+1)//生成一个1~100的数字
//定义一个数组进行排序后输出
//可以用冒泡排序法,但是也可以运用系统提供的方法
var numArray = []int{15,56,98,12,54,35,65}//切片定义
fmt.Println(numArray)
//调用前输出
sort.Ints(numArray)//只能使用切片
fmt.Println(numArray)//调用后输出
var heroslice Heroes//定义一个Heroes的切片类型
for i := 0;i<10;i++{
hero := Heroes{
name : fmt.Sprintf("英雄+%d",rand.Intn(100)+59),
age : rand.Intn(100),
}//循环中定义一个Heroes的类型的实例,再将实例放进heroslice切片当中
heroslice = append(heroslice,hero)//进行赋值上去,对切片进行赋值
}//想要进行排序,那么这一个自定义类型就要满足接口*/
var stues StudentSlice
for i := 1; i < 40; i++ {
stu := student{
name: fmt.Sprintf("Student-%d", i),
age: rand.Intn(18),
scores: rand.Intn(101),
}
stues = append(stues, stu)
}
for _,value :=range stues{
fmt.Printf("学生编号:%s,\t学生成绩 :%d\n",value.name,value.scores,)
}
sort.Sort(stues)
fmt.Println("排序后~")
for index,value :=range stues{
fmt.Printf("学生编号:%s,\t学生成绩 :%d\t排名为%d\n",value.name,value.scores,index + 1)
}
}
实现接口和 vs 继承
继承和实现接口有什么区别吗?
代码实现:
package main
import "fmt"
type Monkey struct {
name string
}
type BirdAble interface{
flying()
}
type FishAble interface{
swimming()
}
func (mokey Monkey) climming(){
fmt.Println("Monkey生来就会爬树~")
}
type LitterMonkey struct {
Monkey
}
func (litterm LitterMonkey) swimming(){
fmt.Printf("%v 通过后天学习,学会了游泳~\n",litterm.name)
}
func (litterm LitterMonkey) flying(){
fmt.Printf("%v 通过后天学习,学会了飞翔~\n",litterm.name)
}
func (litterm LitterMonkey) DriveCar(){
fmt.Printf("%v 通过后天学习,学会了开车~\n",litterm.name)
}
//type monkey struct{
// LitterMonkey
//}
func main(){
var litterMonkey LitterMonkey
litterMonkey.name = "孙行者"
litterMonkey.climming()
litterMonkey.swimming()
litterMonkey.flying()
litterMonkey.DriveCar()
//var monkey monkey
//monkey.name = "kk"
//monkey.DriveCar()
}
对上面代码的说明:
- 当A结构体继承了B结构体,那么A就自动的继承了B结构体的字段和方法,并且可以直接使用
- 当A结构体想要扩展功能(方法)时,同时又不希望去破环继承关系,那么就可以通过实现某一个接口来进行扩展,因此我们可以认为,实现接口时堆积成机制的一种补充
接口和继承解决的解决问题不同
1.继承的价值主要在于:解决代码的复用性和可维护性
2.接口的价值主要在于:设计,设计好各种规范(方法),让其它自定义类型去实现这种方法。
接口比继承更加灵活 Persion Student BiredAble LitterMonkey
接口再一定的程度上实现了代码的解耦
面向对象编程-多态
基本介绍:
变量(实例)具有多种形态。面向对象三种特征,在Go语言当中,多态特征时通过接口来实现的,可以按照同一的接口来调用不同的实现,这是接口变量就呈现了不同的形态。
快速入门:
前面的Usb接口案例,Usb usb ,既可以接收手机变量,也可以接收camera变量,多态特征
接口体现多态的两种形式:
1.多态参数
就前面的usb接口
2.多态数组
通常切片只能存储相同类型的数据,但是运用接口就可以实习储存不一样的类型的数据
代码:
package main
import "fmt"
type A interface {
//这是一个空接口
}
type Aslice []interface{}
func main(){
var aslice Aslice
var a int = 10
var str = "jack"
var f float64 = 2.6
aslice = append(aslice,a,str,f)
fmt.Println(aslice)
fmt.Println(aslice[2])
}
输出样式:
[10 jack 2.6]
2.6//第一个元素时int第二个元素时string类型,第三类型是float64
演示一个案例:给usb数组中,存放Phone结构体和Camera结构体变量
实例说明:
package main
import "fmt"
//声明一个接口
type Usb interface {
Start()
Stop()
}
type Phone struct{
name string
}
func (phone Phone)Start(){
fmt.Println(phone.name,"开始工作···")
}
func (phone Phone)Stop(){
fmt.Println(phone.name,"停止工作····")
}
type Camera struct {
name string
}
func (camera Camera)Start(){
fmt.Println("相机开始工作···")
}
func (camera Camera)Stop(){
fmt.Println("相机停止工作···")
}
type Computer struct{
}
func (cocmputer Computer)working(usb Usb){
usb.Stop()
usb.Start()
}
func main(){
//定义一个usb接口数组,可以存放phone、camera的结构体变量
//这里就体系哪里额多态数组
var usbArr [3]Usb
usbArr[0] = Phone{"vivo"}
usbArr[1] = Phone{"小米"}
usbArr[2] = Camera{"尼康"}
fmt.Println(usbArr)
var computer Computer
computer.working(usbArr[0])
computer.working(usbArr[1])
computer.working(usbArr[2])
}
接口断言
由一个具体的需要引出来了类型断言,如何将一个接口变量,赋给一个自定义类型变量=》引出了类型断言
基本介绍:
类型断言,由于接口是一般类型,不知道具体类型,如果要转成具体类型,就需要使用类型断言
代码实现:
package main
import "fmt"
func main(){
//类型断言的其他案例
var x interface{}
var b2 float32 = 1.1
x = b2//空接口,可以接收所有类型
//x =>float32[使用类型断言]
y :=x.(float32)
fmt.Println(y)
}
- 对上面的代码说明
- 在进行类型断言的时候,如果类型不匹配,就会报panic,因此进行类型断言时,要确保,原来的空接口指向的就是断言的类型
- 如何在进行断言时,带上检测机制,如果成功就ok,否则有人不报panic
package main
import "fmt"
func main(){
//类型断言的其他案例
var x interface{}
var b2 float32 = 1.1
x = b2//空接口,可以接收所有类型
//x =>float32[使用类型断言]
//类型断言,待检测机制
y, ok := x.(float32)
//y返回的时x转换后的值,y时运行后的是否完成的情况
//成功就返回的时true,失败返回的时false
fmt.Println(y,ok)
if value, ok :=x.(float32);ok{
fmt.Println("convert success")
fmt.Printf("y 的类型时%T 值是 %v",value,value)
}else {
fmt.Println("convert fail~")
}
fmt.Println("继续执行~")
}//返回后直接进行判断
类型断言的最佳实践1:
在前面的Usb接口案例做改进:
给Phone结构体一个特有的方法call(),当Usb接口是Phone变量时,还需要