定义

在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. GDI绘制时钟效果,与系统时间保持同步,基于Winform

    2018年工作之余,想起来捡起GDI方面的技术,特意在RichCodeBox项目中做了两个示例程序,其中一个就是时钟效果,纯C#开发.这个CSharpQuartz是今天上午抽出一些时间,编写的,算是偷 ...

  2. spring boot容器启动详解

    目录 一.前言 二.容器启动 三.总结 =======正文分割线====== 一.前言 spring cloud大行其道的当下,如果不了解基本原理那么是很纠结的(看见的都是约定大于配置,但是原理呢?为 ...

  3. python写一个防御DDos的脚本(请安好环境否则无法实验)

    起因: 居然有ddos脚本,怎么可以没防御ddos的脚本! 开始: 1.请执行 install.py安装好DDos-defalte,会在root目录下多出这个文件夹 代码: 2.然后执行fyddos. ...

  4. 【django基础之ORM】

    一.定义 1.什么是ORM? ORM,即Object-Relational Mapping(对象关系映射),它的作用是在关系型数据库和业务实体对象之间作一个映射,这样,我们在具体的操作业务对象的时候, ...

  5. PHP操作MySQL对表增加一列(一个字段)

    2014-03-19 16:59 1471人阅读 评论(0) 收藏 举报 分类: MySQL(12) 对于已经建立好的数据库,在一个已经有字段的表内新加字段可用以下方法: mysql_query(&q ...

  6. removeClass()

    定义和用法 removeClass() 方法从被选元素移除一个或多个类. 注释:如果没有规定参数,则该方法将从被选元素中删除所有类. 语法 $(selector).removeClass(class) ...

  7. Robots.txt - 禁止爬虫

    robots.txt用于禁止网络爬虫访问网站指定目录.robots.txt的格式采用面向行的语法:空行.注释行(以#打头).规则行.规则行的格式为:Field: value.常见的规则行:User-A ...

  8. ip 淘宝ip库 精简版

    <?php header('Content-type: text/html; charset=utf-8'); //根据ip获取城市.网络运营商等信息 function findCityByIp ...

  9. 基于TI CC2650的IPv6 over BLE(BLEach) demo

    虽然BLE 5.0协议理论上已经开始支持IPv6了,但是目前市面上还没有可用的实现IPv6通信的BLE产品. 最近在网上看到一个开源的基于contiki系统,在CC2650上实现的IPv6 over ...

  10. 为什么我不愿意用ECharts

    前言 ECharts是百度一个使用 JavaScript 实现的开源可视化库,提供了创建多种多样的图标方式,包括坐标系,图例,提示,工具箱等基础组件,并在此上构建出折线图.柱状图.散点图.K线图.饼图 ...