Go 接口
接口的定义
-
go的接口类型定义了一组行为。
-
如果某个
类型
实现了某个接口。那么所以使用这个接口的地方,都支持这种类型。
如果一个变量,他实现了接口里的所有方法,那么他就是实现了这个接口
接口的作用
需求
现在有 狗 和 猫 两个结构体,都能叫,如果被 打
这个函数调用了,他们都能叫,如果在函数往里传参的时候,指定是穿进去的什么参数。
使用接口解决这个问题
(按照约定,只包含一个方法的)接口的名字由方法名加 [e]r 后缀组成,例如Printer、Reader、Writer、Logger、Converter 等等。还有一些不常用的方式(当后缀 er 不合适时),比如Recoverable,此时接口名以 able 结尾,或者以 I 开头(像 .NET 或 Java 中那样)。
package main
import "fmt"
type dog struct{}
type cat struct{}
// 声明接口
type speaker interface {
speak() // speak 方法
}
func (d dog) speak() {
fmt.Println("汪汪叫")
}
func (c cat) speak() {
fmt.Println("喵喵叫")
}
func da(x speaker) {
x.speak() // 传进来一个x,无论这个x是什么样式,都打出来
}
func main() {
var dog1 dog
var cat1 cat
da(dog1)
da(cat1)
}
接口的定义
type 接口的名字 interface{
方法名1:(参数1,参数2,参数3)(返回值1,返回值2)
方法名1:(参数1,参数2,参数3)(返回值1,返回值2)
}
猫狗的另一个例子
package main
import "fmt"
type animal interface {
move() // 移动
eat(string) // 吃东西
}
type dog struct { // 先声明 猫和 狗两个实例
name string
feet int
}
type cat struct {
name string
feet int // 几条腿
}
func (c cat) eat(foot string) {
fmt.Println("猫吃啥?", foot) // 猫吃啥?猫吃鱼
}
func (c cat) move() {
fmt.Println("猫跑了")
}
func (d dog) eat(foot string) {
fmt.Println("狗吃啥?", foot) //狗吃东西
}
func (d dog) move() {
fmt.Println("狗跑了")
}
func main() {
var anmin animal // 声明接口
dog1 := dog{
name: "小黑狗",
feet: 4,
}
anmin = dog1
anmin.move()
anmin.eat("骨头")
cat1 := cat{
name: "小黄猫",
feet: 8,
}
anmin = cat1
anmin.eat("鱼")
anmin.move()
}
// 输出
狗跑了
狗吃啥? 骨头
猫吃啥? 鱼
猫跑了
值接受者和指针接受者的区别
当接受者为值类型的时候,你可以往里传指针,但是当接受者是指针类型的时候,你不能往里传值。
package main
import "fmt"
type animal interface {
move() // 移动
eat(string) // 吃东西
}
type dog struct { // 先声明 猫和 狗两个实例
name string
feet int
}
func (d dog) eat(foot string) {
fmt.Println("狗吃啥?", foot) //狗吃东西
}
func (d dog) move() {
fmt.Println("狗跑了")
}
func main() {
var anmin animal // 声明接口
dog1 := dog{
name: "小黑狗",
feet: 4,
}
anmin = dog1
anmin.move()
anmin.eat("骨头")
fmt.Println("****************")
anmin = &dog1
anmin.move()
anmin.eat("骨头")
}
// 输出
狗跑了
狗吃啥? 骨头
****************
狗跑了
狗吃啥? 骨头
值传递的另一个例子
type people interface {
Speak(string) string
}
type Student struct{}
func (s *Student) Speak(think string) string {
if think == "sb" {
return "大帅比"
} else {
return "你好"
}
}
func main() {
var pe people = &Student{}
fmt.Println(pe.Speak("sb")) //只能用指针调用
}
嵌套
结构体的嵌套
上边写的都是多个类型实现同一个接口,实际上也可以一个类型实现多个接口。
type eater interface {
eat(string) // 吃东西
}
type mover interface {
move() // 实现了move这个接口
}
type dog struct { // 先声明 猫和 狗两个实例
name string
feet int
}
func (d dog) eat(foot string) {
fmt.Println("狗吃啥?", foot) //狗吃东西
}
func (d dog) move() {
fmt.Println("狗跑了")
}
dog对应这 mover
和 eater
这两个接口,而且还可以实现接口的嵌套。
一个接口可以嵌套一个或者多个接口
type ReadWrite interface {
Read(b Buffer) bool
Write(b Buffer) bool
}
type Lock interface {
Lock()
Unlock()
}
type File interface {
ReadWrite
Lock
Close()
}
空接口
type 接口名字 interface {} // 里面任何东西都不写
空接口没有必要命名,通常定义为如下形式
interface{} // 空接口
空接口,也就是说所有的类型都实现了这个接口
这样传什么值都可以了。
空接口可以存储任意类型的值
package main
import "fmt"
func main() {
var m1 = make(map[string]interface{}) // 声明m1
m1["name"] = "赵"
m1["age"] = 20
m1["hopy"] = []string{"吃饭", "睡觉"}
fmt.Println(m1)
}
// 输出
map[age:20 hopy:[吃饭 睡觉] name:赵]
package main
import "fmt"
// 空接口作为参数
func f1(x interface{}) {
fmt.Println(x)
fmt.Printf("%T,%v",x,x)
}
func main() {
var m1 = make(map[string]interface{}) // 声明m1
m1["name"] = "赵"
m1["age"] = 20
m1["hopy"] = []string{"吃饭", "睡觉"}
fmt.Println(m1)
f1("你好")
f1(15)
f1(true)
}
// 输出
string,你好15
int,15true
bool,true
8. 把空接口的值取出来
如何取出来呢?就是考猜
package main
import "fmt"
func f1(x interface{}) {
v, ok := x.(string) // 猜他是什么类型
if !ok {
fmt.Println("猜错了")
} else {
fmt.Println(v)
}
}
func main() {
f1(2)
}
// 输出
猜错了