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专门针对网络应用设计和开发方式,以降低开发的复杂性,提高系统的可伸缩性. ...
随机推荐
- 让群辉支持DTS音轨
让群晖Video Station支持DTS音轨的方法原因:因版权问题,群晖Video Station默认不支持DTS音轨,因此默认不能播放使用DTS音轨的影片. 网上搜到好多解决办法,通常是让添加源h ...
- Java Web接入支付宝扫码付款API(使用SDK证书配置properties )
一.支付宝当面付功能Demo 官方文档https://docs.open.alipay.com/194/106078/ ps:因为沙箱环境一经配置了证书公钥则无法重置 第一步下载项目SKD&D ...
- Transaction check error:
Transaction check error: file /etc/my.cnf from install of MariaDB-common-10.3.16-1.el7.centos.x86_6 ...
- thymeleaf中switch case多出一个空行
以下是<thymeleaf3.0.5中文参考手册.pdf>中的代码,官方代码没有具体去查询. <div th:switch="${user.role}"> ...
- excel自学笔记 from av50264533
1.函数公式 MINUTE(serial_number) 函数解读 Serial_number 表示一个时间值,其中包含要查找的分钟 函数公式 NOW() 函数解读 显示出现在的时间 计算通话时 ...
- 分布式消息通信之RabbitMQ_Note
目录 1. RabbitMQ 安装 2. RabbitMQ 应用场景,特性 3. 官网入门指引 4. RabbitMQ 工作模型 5. RabbitMQ 主要的几种交换机类型 6. Java API的 ...
- vue路由传参的三种方式
方式一 通过query方式传参 这种情况下 query传递的参数会显示在url后面 this.$router.push({ path: '/detail', query: { id: id } }) ...
- input文本框禁用历史选择
这里常用的场景是日期控件使用时,下面这个就很难看了 在input中添加autocomplete="off"就可以了 <input type="text" ...
- [转载]Oracle触发器详解
转载自http://blog.csdn.net/indexman/article/details/8023740/ 触发器是许多关系数据库系统都提供的一项技术.在oracle系统里,触发器类似过程和函 ...
- Evaluating Automatically Generated timelines from the Web (paper1)
摘要: 问题:There is a need that 以一个更全面/更综合的方式来展现搜索结果.对此,作者正在开发一个系统,called “Cronopath”,这个系统将产生一个时间线,通过决定每 ...