定义

在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. 移动App,AJAX异步请求,实现简单的增、删、改、查

    用ajax发异步请求时,要注意url."AppServer"为后台项目名,"LoginServlet.action"为web.xml中的<url-patt ...

  2. UEP-级联下拉

    级联查询在UEP中采用动态下拉的形式,cascadeid为关键字,注意jsp页面的id的相互嵌套关系, 数据库字段的数值的设置,和动态下拉SQL语句的书写. <td align="ce ...

  3. IE8兼容border-radius.

    我们知道,CSS3新增的很多简洁优美的属性,比如border-radius.box-shadow.border-image.gradients.RGBA...因为这些属性的出现,我们可以很方便的就写会 ...

  4. ubuntu-apache下隐藏thinkphp入口文件index.php

    按照thinkphp手册中来讲,apache服务器下,隐藏thinkphp入口文件有3步: httpd.conf配置文件中加载了mod_rewrite.so模块 AllowOverride None ...

  5. CSS3 [attribute^=value] 选择器

    设置 class 属性值以 "test" 开头的所有 div 元素的背景色: div[class^="test"] { background:#ffff00; ...

  6. SDP(3):ScalikeJDBC- JDBC-Engine:Fetching

    ScalikeJDBC在覆盖JDBC基本功能上是比较完整的,而且实现这些功能的方式比较简洁,运算效率方面自然会稍高一筹了.理论上用ScalikeJDBC作为一种JDBC-Engine还是比较理想的:让 ...

  7. CCF系列之Z字形扫描(201412-2)

    试题编号:201412-2试题名称:Z字形扫描时间限制: 2.0s内存限制: 256.0MB 问题描述 在图像编码的算法中,需要将一个给定的方形矩阵进行Z字形扫描(Zigzag Scan).给定一个n ...

  8. Mysql索引分析:适合建索引?不适合建索引?【转】

    数据库建立索引常用的规则如下: 1.表的主键.外键必须有索引: 2.数据量超过300的表应该有索引: 3.经常与其他表进行连接的表,在连接字段上应该建立索引: 4.经常出现在Where子句中的字段,特 ...

  9. char (*p)[]和char *p[]的区别

    理解的关键在于: 1. []的优先级高于*,(*p)[]理解为指向一个数组,*(p[])存放指针的数组 2. char (*p)[SIZE]:指向一维数组的指针,一维数组只能有SIZE个元素 char ...

  10. Certificate downloaded from cloudexpress:11443 is invalid

    问题描述: CertificateManagement : Server is not trusted.Received fatal alert: handshake_failure. Now ins ...