Go面向对象
Go语言 接口
## 接口类型 在Go语言中接口(interface)是一种类型,一种抽象的类型。 接口定义了一个对象的行为规范,只定义规范不实现,由具体的对象来实现规范的细节。 interface是一组method的集合,是duck-type programming的一种体现。接口做的事情就像是定义一个协议(规则),只要一台机器有洗衣服和甩干的功能,我就称它为洗衣机。不关心属性(数据), 接口是一个或多个方法签名的集合。 任何类型的方法集中只要拥有该接口'对应的全部方法'签名。 就表示它 "实现" 了该接口,无须在该类型上显式声明实现了哪个接口。 这称为Structural Typing。 所谓对应方法,是指有相同名称、参数列表 (不包括参数名) 以及返回值。 当然,该类型还可以有其他方法。 接口只有方法声明,没有实现,没有数据字段。 接口可以匿名嵌入其他接口,或嵌入到结构中。 对象赋值给接口时,会发生拷贝,而接口内部存储的是指向这个复制品的指针,既无法修改复制品的状态,也无法获取指针。 只有当接口存储的类型和对象都为nil时,接口才等于nil。 接口调用不会做receiver的自动转换。 接口同样支持匿名字段方法。 接口也可实现类似OOP中的多态。 空接口可以作为任何类型数据的容器。 一个类型可实现多个接口。 接口命名习惯以 er 结尾。 >关于接口需要注意的是,只有当有两个或两个以上的具体类型必须以相同的方式进行处理时才需要定义接口。不要为了接口而写接口,那样只会增加不必要的抽象,导致不必要的运行时损耗。 ## 接口定义 - 接口的定义格式如下: ```go type 接口类型名 interface{ 方法名1( 参数列表1 ) 返回值列表1 方法名2( 参数列表2 ) 返回值列表2 … } ``` - 其中: - **接口名:**使用type将接口定义为自定义的类型名。Go语言的接口在命名时,一般会在单词后面添加er,如有写操作的接口叫Writer,有字符串功能的接口叫Stringer等。接口名最好要能突出该接口的类型含义。 - **方法名:**当方法名首字母是大写且这个接口类型名首字母也是大写时,这个方法可以被接口所在的包(package)之外的代码访问。 - **参数列表、返回值列表:**参数列表和返回值列表中的参数变量名可以省略。 - 举个例子: ```go type writer interface{ Write([]byte) error } ``` 当你看到这个接口类型的值时,你不知道它是什么,唯一知道的就是可以通过它的Write方法来做一些事 ## 实现接口 - 一个对象只要全部实现了接口中的方法,那么就实现了这个接口。换句话说,接口就是一个需要实现的方法列表。 ```go // Sayer 接口 type Sayer interface { say() } //定义dog和cat两个结构体: type dog struct {} type cat struct {} // dog实现了Sayer接口 func (d dog) say() { fmt.Println("汪汪汪") } // cat实现了Sayer接口 func (c cat) say() { fmt.Println("喵喵喵") } //因为Sayer接口里只有一个say方法,所以我们只需要给dog和cat 分别实现say方法就可以实现Sayer接口了。 ``` ## 接口类型变量 接口类型变量能够存储所有实现了该接口的实例。 例如上面的示例中,Sayer类型的变量能够存储dog和cat类型的变量。 ```go 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() // 汪汪汪 } ``` ## 值接收者和指针接收者实现接口的区别 ```go type Mover interface { move() } type dog struct {} ``` ```go //值接收者实现接口 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() } ``` > 从上面的代码中我们可以发现,使用值接收者实现接口之后,不管是dog结构体还是结构体指针*dog类型的变量都可以赋值给该接口变量。因为Go语言中有对指针类型变量求值的语法糖,dog指针fugui内部会自动求值*fugui。 ```go //指针接收者实现接口 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接口的是*dog类型,所以不能给x传入dog类型的wangcai,此时x只能存储*dog类型的值。
顶部
收展
底部
[TOC]
目录
Go语言 接口
Go语言 类型与接口关系
Go语言 空接口
相关推荐
Go基础
Go数据类型
Go函数
Go并发编程
Go数据操作