go语言 - 接口

概述

在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

}

类型查询(类型断言)

  • if 判断
  • switch 分支
//类型断言
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()
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值