
在Go中,接口是一组方法的签名. 当类型为接口中的所有方法提供方法实现时,它将实现该接口. 在Go语言中,接口与实现类之间的关系是非侵入性的,也就是说,如果类型想要实现接口,则无需显式声明其实现了接口. 界面中的方法是静默实现的.
界面与我们面前的所有具体类型都不相同. 接口是抽象类型. 当您看到接口类型的值时,您不知道它是什么,唯一知道的是可以通过其方法完成的事情.
接口定义:
type 接口名 interface{
方法名(参数列表)返回值
...
}
如果接口没有任何方法声明,则它是一个空接口. 其用途类似于面向对象的根类型Object,可以将其分配给任何类型的对象.
接口默认值:

接口的默认值为nil. 如果已实现的接口的类型支持它,则可以执行相等操作.
func main() {
var v1, v2 interface{}
fmt.Println(v1 == nil, v1 == v2) // true true
v1 = 100
v2 = 100
fmt.Println(v1 == v2) // true
}
界面的实现
只要所有对象都实现了接口中的方法,就将实现此接口. 换句话说,该接口是需要实现的方法的列表.
构建一个Action界面,创建一个Student类,然后实现Action界面.
type Action interface {
speak()
eat()
sleep()
}
type Student struct {
name string
ID int
}
func (s Student)speak() {
fmt.Println("正在讲话")
}
func (s Student)eat(){
fmt.Println("正在吃东西")
}
func (s Student)sleep() {
fmt.Println("正在睡觉")
}
func main() {
}

要实现一个接口非常简单,只需实现在接口中声明的方法,那么在实现接口之后有什么用?
让我们想象一个场景,您创建两个对象,一个称为支付宝,一个称为微信,这两个对象都具有支付功能. 现在您必须编写一个收集函数,该函数可以对传入的对象执行收集操作,但是现在出现了一个问题,您不知道传入的对象是支付宝还是微信,因此您可能需要在继续之前进行判断收集操作. 可以判断何时只有很少的物体,如果有很多物体该怎么办?
这时,该界面将派上用场. 接口是抽象类型. 当您看到接口类型的值时,您不知道它是什么,唯一知道的是可以通过其方法完成的事情.
因此,我们可以定义付款方式的接口. 该接口声明一种付款方式,然后使用两个对象支付宝和微信来实现在接口中声明的方法. 然后将付款功能的传入参数类型设置为接口类型.
type AliPay struct {
}
type WeChat struct {
}
func (AliPay) Pay() {
fmt.Println("支付宝转账")
}
func (WeChat) Pay() {
fmt.Println("微信转账")
}
type PayMethod interface {
Pay()
}
func GetMoney(p PayMethod) {
p.Pay()
}
func main() {
a := AliPay{}
w := WeChat{}
GetMoney(a)
GetMoney(w)
}
输出为:

支付宝转账
微信转账
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()
}
从上面的代码中我们可以发现,在使用值实现接口之后,无论是狗结构还是结构指针*狗类型变量都可以分配给接口变量. 因为Go语言具有用于评估指针类型变量的语法糖,所以狗指针fugui将在内部自动评估* fugui.
相同的代码,让我们测试使用指针之间的区别:
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类型
}
这时,实现了Mover接口的是*狗类型,因此您不能将狗类型的wangcai传递给x. 目前,x只能存储*狗类型的值.

您可以嵌入其他界面go语言实现短信接口,例如匿名字段. 目标类型方法集必须具有包括嵌入式接口方法在内的所有方法才能实现该接口.
嵌入其他接口类型等同于导入其声明的方法集. 这要求不能有重复的名称方法,因为不支持重载. 另外,您不能嵌入自身或循环嵌入,这将导致递归错误.
type stringer interface {
string() string
}
type tester interface {
stringer
test()
}
type data struct {
}
func (*data) test() {
}
func (data) string() string {
return ""
}
func main() {
var d data
var t tester = &d
t.test()
println(t.string())
}
接口结构如下:
type iface struct {
tab *itab
data unsafe.Pointer
}
Itab存储操作期间所需的相关类型信息.
type itab struct{
inter *interface // 接口类型
_type *_type // 实际对象类型
fun [1]uintptr // 实际对象方法地址
}
Itab存储接口和实际对象的元数据. 同时go语言实现短信接口,itab还使用fun数组保存实际的方法地址,以实现在操作过程中对目标方法的动态调用.
此外,该接口还有一个重要功能: 将一个对象分配给该接口时,将复制该对象.
在接口内部,仅当两个指针(itab和数据)均为nil时,接口才等于nil.
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-220537-1.html
英语系毕业也只能如此
01我觉得好卡啊
脑子烧坏了