funcmain() { var x Sayer // 声明一个Sayer类型的变量x a := cat{} // 实例化一个cat b := dog{} // 实例化一个dog x = a // 可以把cat实例直接赋值给x x.say() // 喵喵喵 x = b // 可以把dog实例直接赋值给x x.say() // 汪汪汪 }
Tips: 观察下面的代码,体味此处_的妙用
1 2 3 4 5 6
// 摘自gin框架routergroup.go type IRouter interface{ ... }
type RouterGroup struct { ... }
var _ IRouter = &RouterGroup{} // 确保RouterGroup实现了接口IRouter
值接收者和指针接收者实现接口的区别
使用值接收者实现接口和使用指针接收者实现接口有什么区别呢?接下来我们通过一个例子看一下其中的区别。
我们有一个Mover接口和一个dog结构体。
1 2 3 4 5
type Mover interface { move() }
type dog struct {}
值接收者实现接口
1 2 3
func(d dog) move() { fmt.Println("狗会动") }
此时实现接口的是dog类型:
1 2 3 4 5 6 7 8
funcmain() { var x Mover var wangcai = dog{} // 旺财是dog类型 x = wangcai // x可以接收dog类型 var fugui = &dog{} // 富贵是*dog类型 x = fugui // x可以接收*dog类型 x.move() }
funcmain() { var x animal x = cat{name: "花花"} x.move() x.say() }
空接口
空接口的定义
空接口是指没有定义任何方法的接口。因此任何类型都实现了空接口。
空接口类型的变量可以存储任意类型的变量。
1 2 3 4 5 6 7 8 9 10 11 12 13
funcmain() { // 定义一个空接口x var x interface{} s := "Hello 沙河" x = s fmt.Printf("type:%T value:%v\n", x, x) i := 100 x = i fmt.Printf("type:%T value:%v\n", x, x) b := true x = b fmt.Printf("type:%T value:%v\n", x, x) }
空接口的应用
空接口作为函数的参数
使用空接口实现可以接收任意类型的函数参数。
1 2 3 4
// 空接口作为函数参数 funcshow(a interface{}) { fmt.Printf("type:%T value:%v\n", a, a) }
funcmain() { var x interface{} x = "Hello 沙河" v, ok := x.(string) if ok { fmt.Println(v) } else { fmt.Println("类型断言失败") } }
上面的示例中如果要断言多次就需要写多个if判断,这个时候我们可以使用switch语句来实现:
1 2 3 4 5 6 7 8 9 10 11 12
funcjustifyType(x interface{}) { switch v := x.(type) { casestring: fmt.Printf("x is a string,value is %v\n", v) caseint: fmt.Printf("x is a int is %v\n", v) casebool: fmt.Printf("x is a bool is %v\n", v) default: fmt.Println("unsupport type!") } }