Go入门(四)接口
什么是接口,只要记住一句,接口是一种类型。
接口应用的场景:我不关心接口的类型,我只关心能调用他的方法。
如果一个变量,他实现了接口里的所有方法,那么他就是实现了这个接口
1.需求
现在有 狗 和 猫 两个结构体,都能叫,如果被 打
这个函数调用了,他们都能叫,如果在函数往里传参的时候,指定是穿进去的什么参数。
package main
import "fmt"
type dog struct{}
type cat struct{}
func (d dog) speak() {
fmt.Println("汪汪叫")
}
func (c cat) speak() {
fmt.Println("喵喵叫")
}
func da(x) {
x.speak() // 这个应该是个什么类型?
}
func main() {
var dog1 dog
var cat1 cat
da(dog1)
}
2.使用接口解决这个问题
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)
}
3.接口的定义
type 接口的名字 interface{
方法名1:(参数1,参数2,参数3)(返回值1,返回值2)
方法名1:(参数1,参数2,参数3)(返回值1,返回值2)
}
4.猫狗的另一个例子
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()
}
// 输出
狗跑了
狗吃啥? 骨头
猫吃啥? 鱼
猫跑了
5.值接受者和指针接受者的区别
当接受者为值类型的时候,你可以往里传指针,但是当接受者是指针类型的时候,你不能往里传值。
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("骨头")
}
// 输出
狗跑了
狗吃啥? 骨头
****************
狗跑了
狗吃啥? 骨头
6.结构体的嵌套
上边写的都是多个类型实现同一个接口,实际上也可以一个类型实现多个接口。
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
这两个接口,而且还可以实现接口的嵌套。
7.空接口
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)
}
// 输出
猜错了