定义

在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基础之--接口的更多相关文章

  1. 速战速决 (4) - PHP: 类基础, 抽象类, 接口, trait

    [源码下载] 速战速决 (4) - PHP: 类基础, 抽象类, 接口, trait 作者:webabcd 介绍速战速决 之 PHP 类基础 抽象类 接口 trait 示例1.类的相关知识点 1(基础 ...

  2. [.net 面向对象编程基础] (16) 接口

    [.net 面向对象编程基础] (16) 接口 关于“接口”一词,跟我们平常看到的电脑的硬件“接口”意义上是差不多的.拿一台电脑来说,我们从外面,可以看到他的USB接口,COM接口等,那么这些接口的目 ...

  3. spring中基础核心接口总结

    spring中基础核心接口总结理解这几个接口,及其实现类就可以快速了解spring,具体的用法参考其他spring资料 1.BeanFactory最基础最核心的接口重要的实现类有:XmlBeanFac ...

  4. Go语言基础之接口

    Go语言基础之接口 接口(interface)定义了一个对象的行为规范,只定义规范不实现,由具体的对象来实现规范的细节. 接口 接口介绍 在Go语言中接口(interface)是一种类型,一种抽象的类 ...

  5. C#基础--类/接口/成员修饰符,多态、重载、重写,静态和非静态

    C#基础--类/接口/成员修饰符,多态.重载.重写,静态和非静态 类/接口/成员修饰符 C#修饰符---接口: 接口默认访问符是internal接口的成员默认访问修饰符是public C#修饰符--类 ...

  6. Java基础十--接口

    Java基础十--接口 一.接口的定义和实例 /* abstract class AbsDemo { abstract void show1(); abstract void show2(); } 8 ...

  7. Java基础-面向接口(interface)编程

    Java基础-面向接口(interface)编程 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.接口的概念 接口是功能的集合,同样可看做是一种数据类型,是比抽象类更为抽象的“类 ...

  8. GO学习-(14) Go语言基础之接口

    Go语言基础之接口 接口(interface)定义了一个对象的行为规范,只定义规范不实现,由具体的对象来实现规范的细节. 接口 接口类型 在Go语言中接口(interface)是一种类型,一种抽象的类 ...

  9. C#夯实基础之接口(《CLR via C#》读书笔记)

    一. 接口的类型 接口是引用类型.因此从值类型赋值给接口是需要装箱的.如下所示: class Program { static void Main(string[] args) { ISay catS ...

  10. Java基础10 接口的继承与抽象类

    链接地址:http://www.cnblogs.com/vamei/archive/2013/03/31/2982240.html 作者:Vamei 出处:http://www.cnblogs.com ...

随机推荐

  1. c++(非递归排序)

    在上面一篇博客当中,我们发现普通查找和排序查找的性能差别很大.作为一个100万的数据,如果使用普通的查找方法,那么每一个数据查找平均下来就要几十万次,那么二分法的查找呢,20多次就可以搞定.这中间的差 ...

  2. powerdesign

  3. 解决CSS垂直居中的几种方法(基于绝对定位,基于视口单位,Flexbox方法)

    在CSS中对元素进行水平居中是非常简单的:如果它是一个行内元素,就对它的父元素应用 text-align: center ;如果它是一个块级元素,就对它自身应用 margin: auto.然而如果要对 ...

  4. ubuntu开启openssh-server,ssh[xshell]

    在虚机中安装了ubuntu,但是从宿主机器上ping 22的端口始终不通,查询原因,虚机只安装了 openssh-client. 运行Terminal $-> sudo apt-get inst ...

  5. [国嵌笔记][013][Mini2440开发板介绍]

    系统资源 处理器:三星 S3C2440A ARM9 内存:64M SDRAM Nor Flash:2MB Nand  Flash:256MB LCD:3.5寸 分辨率320*240 启动模式 从nan ...

  6. 使用Eclipse在Excel中找出两张表中相同证件号而姓名或工号却出现不同的的项

    1:首先把Excel中的文本复制到txt中,复制如下: A表: 证件号                           工号  姓名 310110xxxx220130004 101 傅家宜3101 ...

  7. 科普:String hashCode 方法为什么选择数字31作为乘子

    1. 背景 某天,我在写代码的时候,无意中点开了 String hashCode 方法.然后大致看了一下 hashCode 的实现,发现并不是很复杂.但是我从源码中发现了一个奇怪的数字,也就是本文的主 ...

  8. java finally深入探究

    When---什么时候需要finally: 在jdk1.7之前,所有涉及到I/O的相关操作,我们都会用到finally,以保证流在最后的正常关闭.jdk1.7之后,虽然所有实现Closable接口的流 ...

  9. 虚拟主机导入MySQL出现Unknown character set: ‘utf8mb4’

    http://www.lmlblog.com/14.html 前几天进行网站搬家,MySQL导入数据的时候,出现以下错误(没有定义的编码集utf8mb4): SQL 查询: ; MySQL 返回:文档 ...

  10. CSAPP 第二章随笔

    类型转换问题 (1)int -> short 二进制位高位截断,低位保持不变 (2)同类型 unsign -> sign 记住二进制位是不变的 (3)P101页提到的编译器乘法优化问题,一 ...