接口类型的变量不可以使用其实例的字段
// Sayer 接口
type Sayer interface {
say()
}
type dog struct {
a int
}
// dog实现了Sayer接口
func (d dog) say() {
fmt.Println('汪汪汪')
}
func main() {
var x Sayer
b := dog{
a :4,
}
x = b
x.say()
fmt.Println(x.a) //会编译出错
}
嵌套其他接口时正确实现
type Sayer interface {
Lister
say()
}
type Lister interface {
lis()
}
type cat struct{}
// dog实现了Sayer接口
func (d cat) say() {
fmt.Println('汪汪汪')
}
// cat实现了Sayer接口
func (c cat) lis() {
fmt.Println('喵喵喵')
}
func main() {
var x Sayer // 声明一个Sayer类型的变量x
a := cat{} // 实例化一个cat
x = a // 会报错,原因缺少say方法
x.say() // 汪汪汪
x.lis()
}
空结构体占用16字节
type demo interface {
}
func main() {
var a demo
fmt.Println(unsafe.Sizeof(a)) //输出16
var b interface{}
fmt.Println(unsafe.Sizeof(b)) //输出16
var c complex64
fmt.Println(unsafe.Sizeof(c)) //输出8
}
接口没有数据字段
没有嵌套其他接口时
// Sayer 接口
type Sayer interface {
say()
}
type dog struct{}
type cat struct{}
// dog实现了Sayer接口
func (d dog) say() {
fmt.Println('汪汪汪')
}
// cat实现了Sayer接口
func (c cat) say() {
fmt.Println('喵喵喵')
}
空接口
使用接口的原因
接口的方法错误定义
package main
import (
'fmt'
)
type Phone interface {
call()
}
//会编译报错
func (i Phone) call() {
fmt.Println('q23erg')
}
func main() {
}
接口命名习惯以er结尾
接口类型的变量可使用其实例的方法,但是不可以使用其实例的字段
// Sayer 接口
type Sayer interface {
say()
}
type dog struct {
a int
}
type cat struct{}
// dog实现了Sayer接口
func (d dog) say() {
fmt.Println('汪汪汪')
}
// cat实现了Sayer接口
func (c cat) say() {
fmt.Println('喵喵喵')
}
func main() {
var x Sayer // 声明一个Sayer类型的变量x
a := cat{} // 实例化一个cat
b := dog{} // 实例化一个dog
x = a // 可以把cat实例直接赋值给x
x.say() // 喵喵喵
x = b // 可以把dog实例直接赋值给x
x.say() // 汪汪汪
}
接口内方法不一样时
// Sayer 接口
type Sayer interface {
say()
}
// Mover 接口
type Mover interface {
move()
}
type dog struct {
name string
}
// 实现Sayer接口
func (d dog) say() {
fmt.Printf('%s会叫汪汪汪
', d.name)
}
// 实现Mover接口
func (d dog) move() {
fmt.Printf('%s会动
', d.name)
}
func main() {
var x Sayer
var y Mover
var a = dog{name: '旺财'}
x = a
y = a
x.say() //输出:旺财会叫汪汪汪
y.move() //输出:旺财会动
}
在Go语言中接口是一种类型,一种抽象的类型;interface是一组method的集合,是duck-typeprogramming的一种体现。接口做的事情就像是定义一个协议,只要一台机器有洗衣服和甩干的功能,我就称它为洗衣机。不关心属性,只关心行为;为了保护你的Go语言职业生涯,请牢记接口是一种类型;
上面的代码中定义了猫和狗,然后它们都会叫,你会发现main函数中明显有重复的代码,如果我们后续再加上猪、青蛙等动物的话,我们的代码还会一直重复下去。那我们能不能把它们当成“能叫的动物”来处理呢?像类似的例子在我们编程过程中会经常遇到:比如一个网上商城可能使用支付宝、微信、银联等方式去在线支付,我们能不能把它们当成“支付方式”来处理呢?比如三角形,四边形,圆形都能计算周长和面积,我们能不能把它们当成“形”来处理呢?比如销售、行政、程序员都能计算月薪,我们能不能把他们当成“员工”来处理呢?Go语言中为了解决类似上面的问题,就设计了接口这个概念。接口区别于我们之前所有的具体类型,接口是一种抽象的类型。当你看到一个接口类型的值时,你不知道它是什么,唯一知道的是通过它的方法能做什么
type Cat struct{}
func (c Cat) Say() string { return '喵喵喵' }
type Dog struct{}
func (d Dog) Say() string { return '汪汪汪' }
func main() {
c := Cat{}
fmt.Println('猫:', c.Say())
d := Dog{}
fmt.Println('狗:', d.Say())
}
一个类型可以实现多个接口
空接口可以作为任何类型数据的容器
1只有当接口存储的类型和对象都为nil时接口才等于nil
实现接口条件:接口被实现的条件接口的方法与实现接口的类型方法格式一致接口被实现的条件接口中所有方法均被实现任何类型的方法集中只要拥有该接口’对应的全部方法’签名就表示它“实现”了该接口,无须在该类型上显式声明实现了哪个接口,这称为StructuralTyping;所谓对应方法,是指有相同名称、参数列表(不包括参数名)以及返回值;当然该类型还可以有其他方法
接口只有方法声明,没有实现,没有数据字段
接口可以嵌入到结构体struct里
接口内方法一样时
// Sayer 接口
type Sayer interface {
say()
}
// Mover 接口
type Mover interface {
say()
}
type dog struct {
name string
}
// 实现Sayer接口
func (d dog) say() {
fmt.Printf('%s会叫汪汪汪
', d.name)
}
func main() {
var x Sayer
var y Mover
var a = dog{name: '旺财'}
x = a
y = a
x.say() //输出:旺财会叫汪汪汪
y.say()//输出:旺财会叫汪汪汪
}
接口是一个或多个方法签名的集合
结构体中方法+结构体中所嵌套的结构体的方法来实现接口
类型断言
多个类型实同一接口
// Mover 接口
type Mover interface {
move()
}
type dog struct {
name string
}
type car struct {
brand string
}
// dog类型实现Mover接口
func (d dog) move() {
fmt.Printf('%s会跑
', d.name)
}
// car类型实现Mover接口
func (c car) move() {
fmt.Printf('%s速度70迈
', c.brand)
}
func main() {
var x Mover
var a = dog{name: '旺财'}
var b = car{brand: '保时捷'}
x = a
x.move() //输出:旺财会跑
x = b
x.move() //输出:保时捷速度70迈
}
嵌套其他接口时错误实现
type Sayer interface {
Lister
say()
}
type Lister interface {
lis()
}
type dog struct{}
type cat struct{}
// dog实现了Sayer接口
func (d dog) say() {
fmt.Println('汪汪汪')
}
// cat实现了Sayer接口
func (c cat) lis() {
fmt.Println('喵喵喵')
}
func main() {
var x Sayer // 声明一个Sayer类型的变量x
a := cat{} // 实例化一个cat
b := dog{} // 实例化一个dog
x = a // 会报错,原因缺少say方法
x = b // 会报错,原因缺少lis方法
x.say() // 汪汪汪
}
定义
接口定义
接口里可以含多个接口时
// Sayer 接口
type Sayer interface {
say()
}
// Mover 接口
type Mover interface {
move()
}
// 接口嵌套
type animal interface {
Sayer
Mover
}
type cat struct {
name string
}
func (c cat) say() {
fmt.Println('喵喵喵')
}
func (c cat) move() {
fmt.Println('猫会动')
}
func main() {
var x animal
x = cat{name: '花花'}
x.move()
x.say()
}
结合switch语句
从下面的代码中我们可以发现,使用值接收者实现接口之后,不管是dog结构体还是结构体指针dog类型的变量都可以赋值给该接口变量。因为Go语言中有对指针类型变量求值的语法糖,dog指针fugui内部会自动求值fugui
type Mover interface {
move()
}
type dog struct{}
func (d dog) move() {
fmt.Println('狗会动')
}
func main() {
var x Mover
var wangcai = dog{} // 旺财是dog类型
x = wangcai // x可以接收dog类型
var fugui = &dog{} // 富贵是*dog类型
x = fugui // x可以接收*dog类型
x.move()
}
指针接收者实现接口
接口类型的变量可使用其实例的方法
值接收者实现接口
实现接口的所有方法即可实现接口
此时实现Mover接口的是dog类型,所以不能给x传入dog类型的wangcai,此时x只能存储dog类型的值
type Mover interface {
move()
}
type dog struct{}
func (d *dog) move() {
fmt.Println('狗会动')
}
func main() {
var x Mover
var wangcai = dog{} // 旺财是dog类型
x = wangcai // 这一行会会议报错
var fugui = &dog{} // 富贵是*dog类型
x = fugui // x可以接收*dog类型
x.move()
}
定义要求
接口里可以含一个接口时
v,ok=x.(Y)应用
func main() {
var x interface{}
x = 'pprof.cn'
v, ok := x.(string)
if ok {
fmt.Println(v)
} else {
fmt.Println('类型断言失败')
}
//输出:pprof.cn
}
func main() {
var x interface{}
x = 'pprof.cn'
v, ok := x.(bool)
if ok {
fmt.Println(v)
} else {
fmt.Println('类型断言失败')
}
//输出:类型断言失败
}
接口的方法可以通过在类型中嵌入其他类型或者结构体来实现
// WashingMachine 洗衣机
type WashingMachine interface {
wash()
dry()
}
// 甩干器
type dryer struct{}
// 实现WashingMachine接口的dry()方法
func (d dryer) dry() {
fmt.Println('甩一甩')
}
// 海尔洗衣机
type haier struct {
dryer //嵌入甩干器
}
// 实现WashingMachine接口的wash()方法
func (h haier) wash() {
fmt.Println('洗刷刷')
}
func main() {
var x WashingMachine
var a haier
x = a
x.dry() //输出:甩一甩
}
文章为作者独立观点,不代表股票交易接口观点