前言:
接口是1种以type关键字声明的数据类型
如果想满足这种类型 就必须实现接口中规定的所有方法,从而起到了约束、限定行为的目的。
有了接口的约束 那些自定义struct就更具有规范性,不同的struct遵循了同1套规范并且去遵循这1套规范。
秦始皇一统6个不同国家之后 统一了度量衡、人同文、车同轨。
既方便了现有这些人(原本来自不同国界的人彼此之间相互沟通(调用),也为以后继续开疆扩土打下基础。
package main
import "fmt"
//usb interface规定都要实现 usb接口中的start和end方法都可以称为usb interface类型
type usb interface {
statr()
end()
}
//相机 struct
type camera struct{ brand string }
//相机实现usb interface的start方法
func (c camera) statr() {
fmt.Printf("%s相机插入电脑的USB接口
", c.brand)
}
//相机实现usb interface的end方法
func (c camera) end() {
fmt.Printf("%s相机插入电脑的USB接口
", c.brand)
}
//手机 struct
type phone struct{ brand string }
//手机实现usb interface的start方法
func (p phone) statr() {
fmt.Printf("%s手机插入电脑的USB接口
", p.brand)
}
//手机实现usb interface的end方法
func (p phone) end() {
fmt.Printf("%s手机拔出电脑的USB接口
", p.brand)
}
//电脑 struct
type computer struct{ brand string }
//电脑的usbWork这里体现多态的重点!仅接受usb类型的参数(实现start和end方法就属于usb 接口类型) who cares what kind of ekectronics it is?
func (c computer) usbWork(e usb) {
e.statr()
e.end()
}
func main() {
lenov := computer{brand: "lenov"}
Jphone := phone{brand: "Jphone"}
Soni := camera{brand: "soni"}
lenov.usbWork(Jphone)
lenov.usbWork(Soni)
}
Golang为什么需要 interface 类型
之前使用Python、JavaScript..动态类型的语言较多,对面向对象中多态特的特性感受不是很深刻。
由于Golang是强类型的语言,变量一经声明不存在数据类型自动识别/修改。所以它需要接口规范。
现在我有1个struct human和另1个struct cats它们都有自己共有的属性-feet、方法-move。
如何使这2个struct都可以作为同1种类型的函数参数,传入到1个run函数中,并执行它们共有的方法move(),输出2种动物2种不同的走路方式?
//1.Go中引出接口概念
package main
import "fmt"
/*
定义1个animal接口:只要有类型接口中的规范有move方法,
就可以称之为这种animal interface类型
*/
type animal interface {
move()
}
//hunma 结构体
type human struct {
name string
feet uint8
}
//人类实现了 move方法,就属于animal interface类型
func (h human) move() {
fmt.Printf("%s 使用 %d条腿走路~
", h.name, h.feets)
}
//dogs 猫科动物结构体
type cats struct {
name string
feet uint8
}
//猫科动物实现了move方法,也属于animal interface类型
func (d cats) move() {
fmt.Printf("%s 使用 %d条腿走路~
", d.name, d.feets)
}
/*
run函数接收值为aniaml接口类型的参数
现在human和animal的类型一致(都实现了move方法!)
所有都可以作为参数传到run函数里面
*/
func run(a animal) {
a.move()
}
func main() {
p1 := human{name: "光头强", feet: 2}
var d1 cats
d1.name = "熊二"
d1.feet = 4
run(p1)
run(d1)
}
对不同类型进行接口约束
package main
import (
"fmt"
)
//自行车
type bicycle struct {
brand string
}
//自行车实现得能开
func (b bicycle) drive() {
fmt.Printf("I've got a/an %s
.", b.brand)
}
//四轮汽车也得能开
type car struct {
brand string
}
func (c car) drive() {
fmt.Printf("I've got a/an %s.
", c.brand)
}
//飞机也得能开
type airplane struct {
brand string
}
func (a airplane) drive() {
fmt.Printf("I've got a/an %s.
", a.brand)
}
//定义1个transport 接口类型
type transport interface {
drive()
}
//想要批量生产transport,就得有自己的标准
func factory(t transport) {
t.drive()
}
func main() {
var feige = bicycle{
brand: "飞鸽",
}
var bens = car{
brand: "大奔",
}
var boyin747 = airplane{
brand: "波也",
}
factory(feige)
factory(bens)
factory(boyin747)
}
接口的定义与实现
定义
interface类型可以定义1组方法,但是不需要在接口内部实现这些方法。并且interface内部不能包含任何变量。
哪个自定义类型 (如struct)想要使用哪个接口时,需要把哪个接口中定义的方法全部实现。
type 接口名称 interface {
方法名1(参数1,参数2)(返回值1,返回值2)
方法名2(参数1,参数2)(返回值1,返回值2)
}
实现
Golang中的接口实现起来灵活、低耦合,因为不需要像Java中1个类 class A implement interface b 通过implement关键字来显式实现。
只要 变量A中含有 接口B中定义的所有方法 ,变量A就可以称为interfaceB类型。
接口的使用
接口的使用就是你遵循了该接口中规定的全部标准(实现了接口中定义的方法)之后,你就可以作为该接口类型的变量、参数在Go中畅行无阻的使用。
package main
import "fmt"
//usb interface规定
type usb interface {
statr()
end()
}
//相机 struct
type camera struct{ brand string }
//相机使用指针接收者 实现usb interface的start方法
func (c *camera) statr() {
fmt.Printf("%s相机插入电脑的USB接口
", c.brand)
}
//相机使用指针接收者 实现usb interface的end方法
func (c *camera) end() {
fmt.Printf("%s相机插入电脑的USB接口
", c.brand)
}
//手机 struct
type phone struct{ brand string }
//手机实现usb
func (p phone) statr() {
fmt.Printf("%s手机插入电脑的USB接口
", p.brand)
}
//手机实现usb interface的end方法
func (p phone) end() {
fmt.Printf("%s手机拔出电脑的USB接口
", p.brand)
}
//电脑 struct
type computer struct{ brand string }
func (c computer) usbWork(e usb) {
e.statr()
e.end()
}
func main() {
/*
使用值接收者实现接口和使用值接收者实现接口的区别?:
使用值接收者实现接口的方法:既可以存结构体类型 也能存结构体类型指针的变量
使用指针接收者实现接口的方法:接口只能存储 指针类型的结构体的变量
*/
var u usb
//使用值接收者实现接口的方法:既可以存结构体类型的变量、也可以存结构体指针类型的变量
phone1:=phone{brand:"8848手机"}
phone2:=phone{brand:"乐视手机"}
u=phone1
fmt.Printf("%T
",u)
u=&phone2
fmt.Printf("%T
",u)
//使用指针接收者实现接口的方法:接口只能存储 指针类型的变量
camera1:=&camera{brand:"苏尼"}
u=camera1
fmt.Printf("%T
",u)
}
空接口
空接口interface{ } 就是我没有定义任何方法(规范),任意类型不需要实现任何方法(规范) 就可以作为空接口类型作为变量和参数使用。
为什么 fmt.Print( )函数可以接收任何数据类型呢?
func Println(a ...interface{}) (n int, err error) {
return Fprintln(os.Stdout, a...)
}
//interface{}就是空接口
空接口是指没有定义任何方法的接口。因此任何变量和参数都属于空接口类型。
空接口类型的变量可以存储任意类型的变量。包揽Golang中任何数据类型。
package main
import "fmt"
type everything interface{}
func main(){
var m1 map[string]everything
m1=make(map[string]everything,18)
m1["name"]="阿水"
m1["married"]=true
m1["age"]=19
m1["hobby"]=[]string{"抽烟","喝酒","烫头"}
fmt.Println(m1)
//哈哈.....终于实现Python里面的字典了吧!
}
空接口数据类型断言
如果任何变量和参数都属于空接口类型,那如何在Go中识别参数和变量具体的数据类型呢?这就需要类型断言。
arg.(string) 方式1
arg.(type) 方式2
如果你要使用Golang 重构Cpython,通过空接口我们我们可以把任意数据类型的变量传入1个Python函数中
那么怎么在函数里面判断变量到底数据属于哪个类型呢?
package main
import "fmt"
//类型断言
func assert(arg interface{}){
value,ok:=arg.(string)
if ok{
fmt.Printf("这是字符型值为%s
",value)
}
}
//类型断言2
func evaluate(arg interface{}) {
switch v := arg.(type) {
case string:
fmt.Printf("%v is a string type
", v)
case int:
fmt.Printf("%v is a int type
", v)
case bool:
fmt.Printf("%v is a bool type
", v)
}
}
func main(){
a:="11111"
assert(a)
evaluate(100)
}