Go 接口使用
本文来自:CSDN博客
感谢作者:fengfengdiandia
查看原文:go 接口
Go 语言不是一种 “传统” 的面向对象编程语言:它里面没有类
和继承
的概念。
但是 Go 语言里有非常灵活的接口
概念,通过它可以实现很多面向对象
的特性。
接口
定义了一个 方法的集合
,但是这些方法 不包含实现代码
,它们是 抽象的
,接口里也 不能包含变量
。
定义格式
定义接口的一般格式:
type Namer interface { Method1(param_list) return_type Method2(param_list) return_type ... }
上面的 Namer
就是一个接口类型。
在 Go 语言中 接口
可以有值, 一个 接口类型
的变量或一个 接口值
:var ai Namer
,ai
是一个 multiword
数据结构,它的值是 nil
。
它本质上是一个 指针
,虽然不完全是一回事。指向接口值的指针是非法的
,会导致代码错误。
类型
(比如结构体)实现接口方法集中的方法,实现了 Namer
接口类型的变量可以赋值给 ai
,此时方法表中的指针会指向被实现的接口方法。
实现某个接口的类型,除了实现接口的方法外,还可以有自己的方法。
package main import "fmt" type Shaper interface { Area() float64 // Perimeter() float64 } type Rectangle struct { length float64 width float64 } // 实现 Shaper 接口中的方法 func (r *Rectangle) Area() float64 { return r.length * r.width } // Set 是属于 Rectangle 自己的方法 func (r *Rectangle) Set(l float64, w float64) { r.length = l r.width = w } func main() { rect := new(Rectangle) rect.Set(2, 3) areaIntf := Shaper(rect) fmt.Printf("The rect has area: %f\n", areaIntf.Area()) }
如果去掉 Shaper
中 Perimeter() float64
的注释,编译的时候会遇到下面的错误,这是因为 Rectangle
没有实现 Perimeter()
方法。
cannot convert rect (type *Rectangle) to type Shaper: *Rectangle does not implement Shaper (missing Perimeter method)
多态
1、多个类型可以实现同一个接口。
2、一个类型可以实现多个接口。
下面我们增加一个类型 Triangle
,同样也为它实现 Shaper
接口。
package main import "fmt" type Shaper interface { Area() float64 // Perimeter() float64 } // ==== Rectangle ==== type Rectangle struct { length float64 width float64 } // 实现 Shaper 接口中的方法 func (r *Rectangle) Area() float64 { return r.length * r.width } // Set 是属于 Rectangle 自己的方法 func (r *Rectangle) Set(l float64, w float64) { r.length = l r.width = w } // ==== Rectangle End ==== // ==== Triangle ==== type Triangle struct { bottom float64 hight float64 } func (t *Triangle) Area() float64 { return t.bottom * t.hight / 2 } func (t *Triangle) Set(b float64, h float64) { t.bottom = b t.hight = h } // ==== Triangle End ==== func main() { rect := new(Rectangle) rect.Set(2, 3) areaIntf := Shaper(rect) fmt.Printf("The rect has area: %f\n", areaIntf.Area()) triangle := new(Triangle) triangle.Set(2, 3) areaIntf = Shaper(triangle) fmt.Printf("The triangle has area: %f\n", areaIntf.Area()) }
灵活性
接口的定义是比较灵活的。
假设接口和类型处于不同的包中,只要类型实现了接口中的全部方法,那么它就实现了此接口。
现在我们将 Shaper
的定义放在 shaper 包
下, Rectangle
和 Triangle
的定义放在 test 包
下:
[root@ src]# tree ├── test │ └── test.go ├── main.go └── shaper └── shaper.go
shaper.go
package shaper type Shaper interface { Area() float64 }
test.go
package test // ==== Rectangle ==== type Rectangle struct { length float64 width float64 } // 实现 Shaper 接口的方法 func (r *Rectangle) Area() float64 { return r.length * r.width } // Set 是属于 Rectangle 自己的方法 func (r *Rectangle) Set(l float64, w float64) { r.length = l r.width = w } // ==== Rectangle End ==== // ==== Triangle ==== type Triangle struct { bottom float64 hight float64 } func (t *Triangle) Area() float64 { return t.bottom * t.hight / 2 } func (t *Triangle) Set(b float64, h float64) { t.bottom = b t.hight = h } // ==== Triangle End ==== // main.go package main import ( "fmt" "shaper" "test" ) func main() { rect := new(test.Rectangle) rect.Set(2, 3) areaIntf := shaper.Shaper(rect) fmt.Printf("The rect has area: %f\n", areaIntf.Area()) triangle := new(test.Triangle) triangle.Set(2, 3) areaIntf = shaper.Shaper(triangle) fmt.Printf("The triangle has area: %f\n", areaIntf.Area()) }
现在运行 main.go
看看结果吧,嗯嗯,没什么问题,^_^
The rect has area: 6.000000
The triangle has area: 3.000000
接口嵌套
一个接口可以包含一个或多个其他的接口,这相当于直接将这些内嵌接口的方法列举在外层接口中一样。
比如接口 File
包含了 ReadWrite
和 Lock
的所有方法,它还额外有一个 Close()
方法。
type ReadWrite interface { Read(b Buffer) bool Write(b Buffer) bool } type Lock interface { Lock() Unlock() } type File interface { ReadWrite Lock Close() }
类型断言
假如我现在写了一个结构体类型 MyFile
来实现上面的 File
接口,那么我如何知道 MyFile
是否实现了 File
接口呢?
通常我们使用 类型断言
来测试在某个时刻 varI
是否包含类型 T
的值:
if v, ok : = varI.(T) ; ok { // checked type assertion Process(v) return } // varI is not of type T
如果 v
是 varI
转换到类型 T
的值,ok
会是 true
;否则 v
是类型 T
的零值,ok
是 false
。
// main.go
package main import "fmt" type MyFile struct{} func (m *MyFile) Read() bool { fmt.Printf("Read()\n") return true } // ... // 假设我这里相继实现了 Write(), Lock(),Unlock() 和 Close() 方法 func main() { my := new(MyFile) fIntf := File(my) // 看这里,看这里 if v, ok := fIntf.(*MyFile); ok { v.Read() } }
输出结果是:Read()
要是多个类型实现了同一个接口,比如前面的 areaIntf
,要如何测试呢?
那就要用 type-switch
来判断了。
type-switch 类型判断
switch t := areaIntf.(type) { case *Rectangle: // do something case *Triangle: // do something default: // do something }
Go 接口使用的更多相关文章
- App开发:模拟服务器数据接口 - MockApi
为了方便app开发过程中,不受服务器接口的限制,便于客户端功能的快速测试,可以在客户端实现一个模拟服务器数据接口的MockApi模块.本篇文章就尝试为使用gradle的android项目设计实现Moc ...
- 干货来袭-整套完整安全的API接口解决方案
在各种手机APP泛滥的现在,背后都有同样泛滥的API接口在支撑,其中鱼龙混杂,直接裸奔的WEB API大量存在,安全性令人堪优 在以前WEB API概念没有很普及的时候,都采用自已定义的接口和结构,对 ...
- 12306官方火车票Api接口
2017,现在已进入春运期间,真的是一票难求,深有体会.各种购票抢票软件应运而生,也有购买加速包提高抢票几率,可以理解为变相的黄牛.对于技术人员,虽然写一个抢票软件还是比较难的,但是还是简单看看123 ...
- Java基础Map接口+Collections工具类
1.Map中我们主要讲两个接口 HashMap 与 LinkedHashMap (1)其中LinkedHashMap是有序的 怎么存怎么取出来 我们讲一下Map的增删改查功能: /* * Ma ...
- Java基础Map接口+Collections
1.Map中我们主要讲两个接口 HashMap 与 LinkedHashMap (1)其中LinkedHashMap是有序的 怎么存怎么取出来 我们讲一下Map的增删改查功能: /* * Ma ...
- java基础_集合List与Set接口
List接口继承了Collection的方法 当然也有自己特有的方法向指定位置添加元素 add(索引,添加的元素); 移除指定索引的元素 remove(索引) 修改指定索引的元素 set ...
- 【WCF】自定义错误处理(IErrorHandler接口的用法)
当被调用的服务操作发生异常时,可以直接把异常的原始内容传回给客户端.在WCF中,服务器传回客户端的异常,通常会使用 FaultException,该异常由这么几个东东组成: 1.Action:在服务调 ...
- PHP以接口方式实现多重继承(完全模拟)--学习笔记
1.UML类图: 2.PHP代码: <?php /** * Created by PhpStorm. * User: andy * Date: 16-11-23 * Time: 下午7:57 ...
- 【微框架】Maven +SpringBoot 集成 阿里大鱼 短信接口详解与Demo
Maven+springboot+阿里大于短信验证服务 纠结点:Maven库没有sdk,需要解决 Maven打包找不到相关类,需要解决 ps:最近好久没有写点东西了,项目太紧,今天来一篇 一.本文简介 ...
- 【接口开发】浅谈 SOAP Webserver 与 Restful Webserver 区别
接口,强大,简单,交互,跨越平台 下面简单阐述这两大接口思想 一 REST: REST是一种架构风格,其核心是面向资源,REST专门针对网络应用设计和开发方式,以降低开发的复杂性,提高系统的可伸缩性. ...
随机推荐
- 阶段5 3.微服务项目【学成在线】_day18 用户授权_17-细粒度授权-获取当前用户信息
3.4.1需求分析 要想实现只查询自己的课程信息则需要获取当前用户所属的企业id. 1.认证服务在用户认证通过将用户所属公司id等信息存储到jwt令牌中. 2.用户请求到达资源服务后,资源服务需要取出 ...
- zabbix4.4 (server,proxy,agent)安装部署实战
一. 部署架构图 二. 安装环境及版本信息 操作系统:centos7 zabbix版本: 4.4 mysql: 5.7.28 三.zabbix server安装(192.168.182.132) rp ...
- C#读取带命名空间的xml
首先带有命名空间的xml读取可以使用Xml.Linq,也可以使用xpath,本文将采用xpath的方式解析. 原文参考了:https://www.cnblogs.com/duanjt/p/544054 ...
- SQLite 的简单使用
程序运行结果如下 : 输入name和age,点击"确认插入"按钮,即插入一条记录到数据库. 程序代码如下:(有详细注释,相信大家都看得懂哈!!!) //// ViewContro ...
- iOS技术面试06:应用程序
1.NSRunLoop的实现机制,及在多线程中如何使用 NSRunLoop是IOS消息机制的处理模式 >1.NSRunLoop的主要作用:控制NSRunLoop里面线程的执行和休眠,在有事情做的 ...
- 【c# 学习笔记】索引器
当一个类包含数组成员时,索引器 的使用将大大地简化对类中数组成员的访问.索引器的定义类似于属性,也具有GET访问器和set访问器,如下: [修饰符] 数据类型 this[索引类型 index] { g ...
- 51.Qt-使用ajax获取ashx接口的post数据
由于当前C++项目需要使用ajax库去post调用ashx接口,接口地址如下所示: 需要传递的参数如下: 然后发现qml比较好调用ajax.js库,所以本章通过C++界面去获取qml方法来实现调用as ...
- vue中的$listeners属性作用
一.当组件的根元素不具备一些DOM事件,但是根元素内部元素具备相对应的DOM事件,那么可以使用$listeners获取父组件传递进来的所有事件函数,再通过v-on="xxxx"绑定 ...
- S03_CH05_AXI_DMA_HDMI图像输出
S03_CH05_AXI_DMA_HDMI图像输出 5.1概述 本课程是在前面课程基础上添加HDMI IP 实现HDMI视频图像的输出.本课程出了多了HDMI输出接口,其他内容和<S03_CH0 ...
- Mybatis-Plus myBatis的增强工具
1. Mybatis-Plus简介 1.1. 什么是Mybatis-Plus MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为 ...