在Go语言的实际编程中,接口是go语言中所有数据结构的核心,几乎所有的数据结构都围绕接口展开
接口是一种契约,详细描述了类型的行为,规定类型可以做什么;并将类型的行为定义和行为实现完全的分离开来,使得相同接口的变量再不同时刻表现出不同的行为,即多态;
Go 语言中的接口是一些方法的集合(Method Set), 判断一种类型是否实现了某一个接口,只需要看该类型是否实现了接口中定义的所有方法
接口是一个或多个方法签名的集合,任何类型的方法集中只要拥有与之对应的全部方法,就表示其“实现”了该接口,无须再该类型上显示添加接口声明;
对应的方法是指:具有相同名称、参数列表(不包括参数名称)以及返回值
1. 接口命名习惯以 er 结尾
2. 接口只有方法签名, 没有具体的实现
3. 接口没有数据字段
4. 可以在接口中嵌入其他接口
5. 类型可以实现多个接口
6. 空接口interface{} 没有任何方法签名,也就意味着任何类型都实现了空接口;类似Java 中的Object 根对象
鸭子类型(duck-typing)
go 通过接口实现了鸭子类型,“当看到一个对象,走起来像鸭子、游泳像鸭子、叫起来像鸭子.....那么这个对象就可以被称为鸭子”;go 语言中,我们不关心对象到底是什么类型,到底是不是鸭子,只关心行为
接口定义了一组方法集合,只有方法的声明,没有具体的实现;
tips: 接口定义中不能包含成员(或者说是“变量”)
//定义一个接口 Humaner 人类, 人类通常都会打招呼 sayHello
type Humaner interface {
SayHello() string
}
//定义一个工程师的类型,并实现 Humaner 接口
type Engineer struct {
name string
gender string //male or female
developLanguage string //java or golang or python or c++ or c
}
//Engineer 实现 Humaner接口
func (engineer Engineer) SayHello() string {
return fmt.Sprintf("Hello World by %s \n", engineer.developLanguage)
}
//定义一个 Teacher 的类型
type Teacher struct {
name string
gender string
course string //语文, 熟悉, 英语
}
//Teacher 实现 Humaner 接口
func (teacher Teacher) SayHello() string {
return fmt.Sprintf("Hello, 我们今天继续上 %s 课 \n", teacher.course)
}
//自定义基础类型, 并实现接口
type MyString string
//MyString 实现 Humaner接口
func (myStr MyString) SayHello() string {
return fmt.Sprintf("Hello, I'm %s \n", myStr)
}
func main() {
var iHuman Humaner
iHuman = Engineer{"Ryan.xu", "male", "golang"}
s := iHuman.SayHello()
fmt.Println("Engineer: ", s)
iHuman = Teacher{"Paul", "male", "英语"}
s = iHuman.SayHello()
fmt.Println("Teacher: ", s)
var myStr MyString
myStr = "Robot"
iHuman = myStr
s = iHuman.SayHello()
fmt.Println("Robot: ", s)
}
//定义一个普通函数, 函数的参数为Humaner 接口类型
func whoIsSayHello(i Humaner) {
var o string = i.SayHello()
fmt.Println(o)
}
func main() {
e := &Engineer{"Anne", "female", "python"}
t := &Teacher{"Linda", "female", "语文"}
var str MyString = "Robot2"
whoIsSayHello(e)
whoIsSayHello(t)
whoIsSayHello(str)
}
//定义一个接口 Humaner 人类, 人类通常都会打招呼 sayHello
type Humaner interface {
SayHello() string
}
//超集, Humaner被嵌入,算子集
type Personer interface {
Humaner //匿名字段, 默认继承了 SayHello 方法
SayByebye(words string) string //有打招呼, 就有说再见, 正所谓人生无不散的筵席
}
/定义一个工程师的类型
type Engineer struct {
name string
gender string //male or female
developLanguage string //java or golang or python or c++ or c
}
//Engineer 实现 Humaner接口
func (engineer Engineer) SayHello() string {
return fmt.Sprintf("Hello World by %s \n", engineer.developLanguage)
}
//Engineer 实现 Personer接口中的 SayByebye 方法
func (engineer Engineer) SayByebye(words string) string {
return fmt.Sprintf("Engineer says byebye with %s", words)
}
func main() {
//接口嵌入
var person Personer
person = Engineer{"Anna", "female", "java"}
//SayByebye 方法
byebyeWords := person.SayByebye("good game")
fmt.Println(byebyeWords)
//SayHello 方法
helloWords := person.SayHello()
fmt.Println(helloWords)
}
func main() {
var iHuman Humaner
iHuman = Teacher{"Paul", "male", "英语"}
s = iHuman.SayHello()
fmt.Println("Teacher: ", s)
var person Personer
person = Engineer{"Anne", "female", "Java"}
//接口转换, 超集可以转换为子集, 子集不能转换为超集, 因为超集的方法比子集多
iHuman = person
fmt.Println("### 接口转换(超集 转为 子集) ###", iHuman.SayHello())
//error : connot use iHuman (type Humaner) as type Personer in assignment
//person = iHuman
}
//类型断言
func typeSearch() {
datas := make([]interface{}, 3)
datas[0] = 1
datas[1] = "hello go"
datas[2] = Engineer{"Jack", "male", "27"}
//if 判断
for i, data := range datas {
if value, ok := data.(int); ok {
fmt.Printf("datas[%d] 的类型为 int, 内容为: %d \n", i, value)
} else if value, ok := data.(string); ok {
fmt.Printf("datas[%d] 的类型为 string, 内容为: %s \n", i, value)
} else if value, ok := data.(Engineer); ok {
fmt.Printf("datas[%d] 的类型为 Engineer, 内容为: %v \n", i, value)
}
}
//switch 分支
for i, data := range datas {
switch value := data.(type) {
case int:
fmt.Printf("datas[%d] 的类型为 int, 内容为: %d \n", i, value)
case string:
fmt.Printf("datas[%d] 的类型为 string, 内容为: %s \n", i, value)
case Engineer:
fmt.Printf("datas[%d] 的类型为 Engineer, 内容为: %v \n", i, value)
}
}
}
func main() {
//类型查询
typeSearch()
}