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专门针对网络应用设计和开发方式,以降低开发的复杂性,提高系统的可伸缩性. ...
随机推荐
- MySql 里的IFNULL用法
IFNULL(expr1,expr2)的用法: 假如expr1 不为 NULL,则 IFNULL() 的返回值为 expr1; 否则其返回值为expr2.IFNULL()的返回值是数字或是字符串,具体 ...
- web端安全测试工具
https://www.cnblogs.com/ios9/p/7692373.html 十大web安全扫描工具 扫描程序可以在帮助造我们造就安全的Web 站点上助一臂之力,也就是说在黑客“黑”你之前, ...
- Mac下载工具软件提示损坏
今天装Navicat的时候一直报错文件损坏,最后请教别人才知道,这里记录下: 原因: Mac默认不允许任何来源的软件安装,安全问题,需要我们设置下即可: 解决方法: 方法一: 方法二: 终端输入命令: ...
- jQuery BlockUI Plugin Demo 3(Page Blocking Examples)
This page demonstrates several ways to block the page. Each button below activates blockUI and then ...
- Tinymce在ASP.NET中的使用方法
现在做网页,用FCKEditor用得比较多,它的实现原理是在要加入FCKEditor的地方加入一个iframe,并将其src指向FCKeditor/editor/fckeditor.html?Inst ...
- 【ARTS】01_32_左耳听风-201900617~201900623
ARTS: Algrothm: leetcode算法题目 Review: 阅读并且点评一篇英文技术文章 Tip/Techni: 学习一个技术技巧 Share: 分享一篇有观点和思考的技术文章 Algo ...
- iOS-NSString值为Unicode格式(字符串编码转换成中文编码)
+ (NSString *)replaceUnicode:(NSString *)unicodeStr { NSString *tempStr1 = [unicodeStrs ...
- eclipse 解决POM文件错误:org.apache.maven.archiver.MavenArchiver.getManifest(org.apache.maven.project.MavenProject, org.apache.maven.archiver.MavenArchiveConfiguration)
解决方案: 更新eclipse中的maven插件 1.1 Help -> Install New Software -> Add 1.2 Location中输入 http://repo1. ...
- Flutter运行报错 `kernel_snapshot for errors` 解决方案
Flutter运行报错 `flutter kernel_snapshot for errors`解决方案 当你Flutter项目删除了dart文件如果遇到 target:kernel_snapshot ...
- 使用AndEngine重制《是男人就上一百层》
1.为什么还要做<是男人就上一百层> 一是在用Android原生API开发完<是男人就上一百层>以后,一直想体验一下用引擎开发游戏是个什么感觉,顺便也让游戏听上去高大上一些(使 ...