Go基础之--接口
定义
在Go语言中,一个类只要实现了接口要求的所有函数,我们就说这个类实现了该接口
interface类型可以定义一组方法,用来表示一个对象的行为特征,interface不能包含任何变量,接口是引用类型。
举个简单的例子,一个动物的接口,动物有吃的能力,有叫的能力,等等,这里省略,假如动物就只有吃和叫的能力。
package main import "fmt" type Animal interface {
Eat()
Talk()
} type Dog struct{ } func (d *Dog) Eat(){
fmt.Println("dog eating.....")
} func (d *Dog) Talk(){
fmt.Println("dog talking....")
} type Cat struct{ } func (d *Cat) Eat(){
fmt.Println("cat eating.....")
} func (d *Cat) Talk(){
fmt.Println("cat talking....")
} func main(){
var d Dog var a Animal
a = &d
a.Eat()
a.Talk() var c Cat
a = &c
a.Eat()
a.Talk()
}
上面这个例子中,Cat和Dog实现了Animal的所有方法,所以Cat和Dog都是动物
小结一下:
Go中的接口不需要显示的实现,只要一个对象实现了接口类型中的所有方法,那么这个对象就实现了这个接口,当然如果一个对象实现了多个interface类型的方法,那么这个对象就实现了多个接口
用于理解接口的一个例子
我们都知道现在的手机有很多支付方式,如:微信支付,支付宝支付,银联支付等等,这里可以通过一个实现支付接口的例子来理解接口
// 定义一个支付的接口
type Pay interface {
pay(userId int64,money float32) error
} // 这里定义一个struct
type AliPay struct { }
// 这里给AliPay添加一个支付方法,实现了Pay接口中的pay方法
func (a *AliPay) pay(userId int64,money float32) error{
fmt.Println("1.连接到阿里支付的服务器")
fmt.Println("2.连接到对应的用户")
fmt.Println("3.检查余额")
fmt.Println("4.扣钱")
fmt.Println("5.返回支付是否成功") return nil
} // 微信支付
type WeChatPay struct { } // 这里也是实现了Pay接口中的pay方法
func (w *WeChatPay) pay(userId int64,money float32) error{
fmt.Println("1.连接到微信支付的服务器")
fmt.Println("2.连接到对应的用户")
fmt.Println("3.检查余额")
fmt.Println("4.扣钱")
fmt.Println("5.返回支付是否成功") return nil
} // 这里定义一个手机struct,并通过字典方式存储自己开通的支付方式
type Phone struct {
PayMap map[string]Pay
} func (p *Phone) OpenWeChatPay(){
weChatPay := &WeChatPay{}
p.PayMap["weChatPay"] = weChatPay
} func (p *Phone) OpenAliPay(){
AliPay := &AliPay{}
p.PayMap["aLiPay"] = AliPay
} func (p *Phone) PayMoney(name string,money float32)(err error){
pay,ok:= p.PayMap[name]
if !ok{
err = fmt.Errorf("不支持【%s】支付方式",name)
return
}
err = pay.pay(1024,money)
return
} func main(){
// 这里切记 字典类型的数据是需要初始化的
phone := &Phone{
PayMap:make(map[string]Pay,10),
} // 这里是用于开通自己有哪些支付方式
//phone.OpenWeChatPay()
phone.OpenAliPay() err := phone.PayMoney("weChatPay",100)
if err != nil{
// 如果微信支付失败了,用支付宝支付
fmt.Printf("支付失败,失败原因:%v\n",err)
fmt.Println("使用支付宝支付")
err = phone.PayMoney("aLiPay",100)
if err != nil{
fmt.Printf("支付失败,失败原因:%v\n",err)
return
}
}
fmt.Println("支付成功,欢迎再次光临")
}
当然可以把上面中关于开通支付方式的两个方法,用一个通用的方法实现,如:
func (p *Phone) OpenPay(name string,pay Pay){
// 可以把上面两个方法更改为这一个方法
p.PayMap[name] = pay
}
空接口
空接口没有任何方法,所有的类型都实现了空接口,空接口什么类型都可以存,如下例子:
package main import "fmt" func main() {
// 通过这个例子我们可以发现我们定义的一个空接口可以存任何类型的变量
var a interface{}
var b int = 10
a = b
fmt.Println(a) var c string = "hello"
a = c
fmt.Println(a)
}
接口的嵌套
一个接口可以嵌套在另外的接口里面,同时一个接口也可以嵌套多个接口
通过下面的例子来理解接口嵌套的概念
package main import "fmt" // 这里定义一个Eater接口
type Eater interface {
Eat()
} // 这里定义一个Talker接口
type Talker interface {
Talk()
} // 这里定义个动物的接口,同时嵌套了Eater和Talker接口
type Animal interface {
Eater
Talker
} // 这里定义一个Dog的struct,并实现talk方法和eat方法,这样就实现了动物的接口
type Dog struct { } func (d *Dog) Talk(){
fmt.Println("talk....")
} func (d *Dog) Eat(){
fmt.Println("eating....")
} func main() {
d := &Dog{}
var a Animal
a = d
a.Eat()
a.Talk()
}
类型断言
如果我们反向想要知道这个接口变量里面实际存储的是哪个类型的对象,可以用下面方法:
通过下面这个例子理解:
package main import (
"fmt"
) type Animal interface {
Eat()
Talk()
} type Dog struct{ } func (d *Dog) Eat(){
fmt.Println("dog eating.....")
} func (d *Dog) Talk(){
fmt.Println("dog talking....")
} type Cat struct{ } func (c *Cat) Eat(){
fmt.Println("cat eating.....")
} func (c *Cat) Talk(){
fmt.Println("cat talking....")
} func justify(a Animal){
// 进行强制转换,如果转换失败则提示错误
dog,ok := a.(*Dog)
if !ok{
fmt.Println("convert to dog failed")
return
}
dog.Eat()
} func main() {
// 分别实例化一个Dog和Cat,并通过justify来进行判断
d := &Dog{}
var a Animal
a = d
a.Eat()
justify(a) c := &Cat{}
a = c
justify(a)
}
再写一个例子,用于判断函数中传入的参数的类型:
package main import (
"fmt"
)
// 这里通过...interface{}表示传入的是可变参数
func justify(items ...interface{}){
for index,v := range items{
//v.(type)表示获取变量的类型
switch v.(type){
case int:
fmt.Printf("第%d个参数is int\n",index)
case float32:
fmt.Printf("第%d个参数is float32\n",index)
case string:
fmt.Printf("第%d个参数is string\n",index)
}
}
} func main() {
var a float32
var b string
var c int
justify(a,b,c)
}
关于猫和狗代码例子中justify方法还可以更改为:
func justify2(a Animal){
switch t:=a.(type){
case *Dog:
t.Eat()
fmt.Printf("t is Dog\n")
case *Cat:
t.Eat()
fmt.Printf("t is Cat\n")
} }
判断一个变量是否实现了指定的接口
在最开始的时候写了一个关于理解接口的例子,如果我们现在想要判断一个变量是否实现了指定的支付的接口,可以通过如下代码实现
weChat := &WeChatPay{}
// 这里需要一个空接口
var tmp interface{} = weChat
_,ok := tmp.(Pay)
if ok{
fmt.Println("weChat is implement Pay interface")
}
Go基础之--接口的更多相关文章
- 速战速决 (4) - PHP: 类基础, 抽象类, 接口, trait
[源码下载] 速战速决 (4) - PHP: 类基础, 抽象类, 接口, trait 作者:webabcd 介绍速战速决 之 PHP 类基础 抽象类 接口 trait 示例1.类的相关知识点 1(基础 ...
- [.net 面向对象编程基础] (16) 接口
[.net 面向对象编程基础] (16) 接口 关于“接口”一词,跟我们平常看到的电脑的硬件“接口”意义上是差不多的.拿一台电脑来说,我们从外面,可以看到他的USB接口,COM接口等,那么这些接口的目 ...
- spring中基础核心接口总结
spring中基础核心接口总结理解这几个接口,及其实现类就可以快速了解spring,具体的用法参考其他spring资料 1.BeanFactory最基础最核心的接口重要的实现类有:XmlBeanFac ...
- Go语言基础之接口
Go语言基础之接口 接口(interface)定义了一个对象的行为规范,只定义规范不实现,由具体的对象来实现规范的细节. 接口 接口介绍 在Go语言中接口(interface)是一种类型,一种抽象的类 ...
- C#基础--类/接口/成员修饰符,多态、重载、重写,静态和非静态
C#基础--类/接口/成员修饰符,多态.重载.重写,静态和非静态 类/接口/成员修饰符 C#修饰符---接口: 接口默认访问符是internal接口的成员默认访问修饰符是public C#修饰符--类 ...
- Java基础十--接口
Java基础十--接口 一.接口的定义和实例 /* abstract class AbsDemo { abstract void show1(); abstract void show2(); } 8 ...
- Java基础-面向接口(interface)编程
Java基础-面向接口(interface)编程 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.接口的概念 接口是功能的集合,同样可看做是一种数据类型,是比抽象类更为抽象的“类 ...
- GO学习-(14) Go语言基础之接口
Go语言基础之接口 接口(interface)定义了一个对象的行为规范,只定义规范不实现,由具体的对象来实现规范的细节. 接口 接口类型 在Go语言中接口(interface)是一种类型,一种抽象的类 ...
- C#夯实基础之接口(《CLR via C#》读书笔记)
一. 接口的类型 接口是引用类型.因此从值类型赋值给接口是需要装箱的.如下所示: class Program { static void Main(string[] args) { ISay catS ...
- Java基础10 接口的继承与抽象类
链接地址:http://www.cnblogs.com/vamei/archive/2013/03/31/2982240.html 作者:Vamei 出处:http://www.cnblogs.com ...
随机推荐
- 启动redis
方法一:默认是前端启动 默认端口:6379 cd /usr/local/redis/bin/redis-server 方法二:后端启动 方法二:后端启动 然后进入 指定配置文件 [roo ...
- JS——判断一个对象是否为空
判断一个对象是否为空对象,本文给出三种判断方法: 1.最常见的思路,for...in...遍历属性,为真则为"非空数组":否则为"空数组" 2.通过JSON自带 ...
- UEP-级联查询
级联查询在UEP中采用动态下拉的形式,cascadeid为关键字,注意jsp页面的id的相互嵌套关系,数据库字段的数值的设置,和动态下拉SQL语句的书写.本功能实现了省市区的三级联动查询
- node中定时器, process.nextTick(), setImediate()的区别与联系
1.定时器 setTimeout()和setInterval()与浏览器中的API是一致的,定时器的问题在于,他并非精确的(在容忍范围内).尽管事件循环十分快,但是如果某一次循环占用的时间较多,那么下 ...
- 关于OELD屏显示电池电量的简易方法
如何采集电源电压大家可能都熟悉,stm32的ADC+DMA能很方便迅速的帮我们采集到自己想要的电压数据.使用DMA进行数据搬运也能很好的减轻CPU的一部分压力.但是这样只是第一步--数据. 用户想看到 ...
- dedecms v5.7 图片集“图集内容”无法调用的解决办法
在dedecms的图片集模型或者基于图片集模型修改的自定义模型中 内容页模板使用 {dede:field.body/} 方式来调用body字段是没有输出的(原因不明,未继续深入) 但有些时候当需要在内 ...
- CCNA -OSI七层模型
OSI (开放系统互联(Open System Interconnection)) OSI是Open System Interconnection的缩写,意为开放式系统互联.国际标准化组织(ISO)制 ...
- Centos6.9安装Node.js+npm爬坑
Node.js选择 1.下载 wget https://nodejs.org/dist/v8.4.0/node-v8.4.0-linux-x86.tar.gz 2.解压 tar zxvf node-v ...
- 使用异步方法在XAML中绑定系统时间
最近的工作需要在程序界面上显示实时的系统时间,网上查了查大部分都是用Timer或者线程来实现. 个人非常不喜欢用Timer,感觉这东西有点太耗资源,然后思考了下觉得更好的方法应该是使用异步的方法在委托 ...
- Windbg+VirtualBox双机调试环境配置(XP/Win7/Win10)
一.下载WDK10 https://developer.microsoft.com/zh-cn/windows/hardware/windows-driver-kit 安装Windows驱动程序工具包 ...