接口的引入
【1】代码入门:
package main
import "fmt"
//接口的定义:定义规则、定义规范,定义某种能力:
type SayHello interface{
sayHello()
}
//接口的实现:定义一个结构体:
//中国人:
type Chinese struct{
}
//实现接口的方法---》具体的实现:
func (person Chinese) sayHello(){
fmt.Println("你好")
}
//接口的实现:定义一个结构体:
//美国人:
type American struct{
}
//实现接口的方法---》具体的实现:
func (person American) sayHello() {
fmt.Println("hi")
}
//定义一个函数:专门用来各国人打招呼的函数,接收具备SayHello接口的能力的变量:
func greet(s SayHello) {
s.sayHello()
}
func main(){
c := Chinese{}
a := American{}
greet(c)
greet(a)
}
【2】总结:
(1)接口中可以定义一组方法,但不需要实现,不需要方法体。并且接口中不能包含任何变量。到某个自定义类型要使用的时候(实现接口的时候),再根据具体情况把这些方法具体实现出来。
(2)实现接口要实现所有的方法才是实现。
(3)Golang中的接口不需要显式的实现接口。Golang中没有implement关键字。
(Golang中实现接口是基于方法的,不是基于接口的)
例如:
A接口 a,b方法
B接口 a,b方法
C结构体 实现了 a,b方法 ,那么C实现了A接口,也可以说实现了B接口 (只要实现全部方法即可,和实际接口耦合性很低,比Java松散得多)
(4)接口目的是为了定义规范,具体由别人来实现即可。
接口注意事项
【1】接口本身不能创建实例,但是可以指向一个实现了该接口的自定义类型的变量。
// 直接用接口创建实例,出错:
// var s SayHello
// s.sayHello()
【2】只要是自定义数据类型,就可以实现接口,不仅仅是结构体类型。
type integer int
func (i integer) sayHello() {
fmt.Println("say hi + ",i)
}
func main(){
var i integer = 10
s = i
s.sayHello()
}
【3】一个自定义类型可以实现多个接口
package main
import "fmt"
type AInterface interface{
a()
}
type BInterface interface{
b()
}
type Stu struct{
}
func (s Stu) a() {
fmt.Println("this is a()")
}
func (s Stu) b() {
fmt.Println("this is b()")
}
func main() {
var s Stu;
var a AInterface = s
var b BInterface = s
a.a()
b.b()
}
【4】一个接口(比如A接口)可以继承多个别的接口(比如B,C接口),这时如果要实现A接口,也必须将B,C接口的方法也全部实现。
package main
import "fmt"
type CInterface interface{
c()
}
type BInterface interface{
b()
}
type AInterface interface{
CInterface
BInterface
a()
}
type Stu struct{
}
func (s Stu) a() {
fmt.Println("a")
}
func (s Stu) b() {
fmt.Println("b")
}
func (s Stu) c() {
fmt.Println("c")
}
func main() {
var s Stu
var a AInterface = s
a.a()
a.b()
a.c()
}
【5】interface类型默认是一个指针(引用类型),如果没有对interface初始化就使用,那么会输出nil
【6】空接口没有任何方法,所以可以理解为所有类型都实现了空接口,也可以理解为我们可以把任何一个变量赋给空接口。
type E interface {
}
func main() {
var e E = s
fmt.Println(e)
var e2 interface{} = s
fmt.Println(e2)
var num float32 = 9.99
var e3 interface{} = num
fmt.Println(e3)
}
多态
【1】基本介绍
变量(实例)具有多种形态。面向对象的第三大特征,在Go语言,多态特征是通过接口实现的。可以按照统一的接口来调用不同的实现。这时接口变量就呈现不同的形态。
【2】案例:
//定义一个函数:专门用来各国人打招呼的函数,接收具备SayHello接口的能力的变量:
func greet(s SayHello) {
s.sayHello()
}
【3】接口体现多态特征
1) 多态参数: s叫多态参数
2) 多态数组 :
比如:定义SayHello数组,存放中国人结构体、美国人结构体
var arr [3]SayHello
arr[0] = American{"Rose"}
arr[1] = Chinese{"菜园子"}
arr[2] = Chinese{"蜘蛛侠"}
fmt.Println(arr)
断言
【1】什么是断言?
Go语言里面有一个语法,可以直接判断是否是该类型的变量: value, ok := element.(T),这里value就是变量的值,ok是一个bool类型,element是interface变量,T是断言的类型。
【2】断言的案例引入:
package main
import "fmt"
type SayHello interface{
sayHello()
}
type Chinese struct{
name string
}
func (person Chinese) sayHello(){
fmt.Println("你好")
}
func (person Chinese) niuYangGe(){
fmt.Println("扭秧歌")
}
type American struct{
name string
}
func (person American) sayHello(){
fmt.Println("hi")
}
//定义一个函数:专门用来各国人打招呼的函数,接收具备SayHello接口的能力的变量:
func greet(s SayHello) {
s.sayHello()
//断言:
//看s是否能转成Chinese类型并且赋给ch变量,flag是判断是否转成功
var ch Chinese = s.(Chinese)
ch.niuYangGe()
fmt.Println("打招呼")
}
func main() {
c := Chinese{}
greet(c)
// a := American{}
// greet(a)
}
解决第二个返回值问题:
//定义一个函数:专门用来各国人打招呼的函数,接收具备SayHello接口的能力的变量:
func greet(s SayHello) {
s.sayHello()
//断言:
//看s是否能转成Chinese类型并且赋给ch变量,flag是判断是否转成功
// var ch Chinese = s.(Chinese)
// ch.niuYangGe()
ch,flag := s.(Chinese)
if flag == true {
ch.niuYangGe()
} else {
fmt.Println("美国人不会扭秧歌")
}
fmt.Println("打招呼")
}
【3】Type Switch 的基本用法
Type Switch 是 Go 语言中一种特殊的 switch 语句,它比较的是类型而不是具体的值。它判断某个接口变量的类型,然后根据具体类型再做相应处理。
func (person American) disco() {
fmt.Println("野狼disco")
}
//定义一个函数:专门用来各国人打招呼的函数,接收具备SayHello接口的能力的变量:
func greet(s SayHello) {
s.sayHello()
//断言:
//看s是否能转成Chinese类型并且赋给ch变量,flag是判断是否转成功
// var ch Chinese = s.(Chinese)
// ch.niuYangGe()
// ch,flag := s.(Chinese)
// if flag == true {
// ch.niuYangGe()
// } else {
// fmt.Println("美国人不会扭秧歌")
// }
switch s.(type) {
case Chinese:
ch := s.(Chinese)
ch.niuYangGe()
case American:
am := s.(American)
am.disco()
}
fmt.Println("打招呼")
}