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专门针对网络应用设计和开发方式,以降低开发的复杂性,提高系统的可伸缩性. ...
随机推荐
- Oracle 表的行数、表占用空间大小,列的非空行数、列占用空间大小 查询
--表名,表占用空间大小(MB),行数select table_name, round(num_rows * avg_row_len /1024/1024, 8) as total_len, num_ ...
- 普罗米修斯Prometheus监控安装
普罗米修斯Prometheus监控安装 架构: 服务端:192.168.0.204 客户端:192.168.0.206 环境准备:所有节点安装go 语言环境 rz go1.12.linux-amd64 ...
- Spring Boot使用JDBC方式连接MySQL
首先去spring官网下载一个名为test的Spring Boot项目模板:https://start.spring.io/ 然后在mysql中的testdb数据库中新建一张名为test_user的表 ...
- iOS-UIButton分类扩展(封装)
UIButton+BackgroundColor.h #import <UIKit/UIKit.h> @interface UIButton (BackgroundColor) - (vo ...
- Tesnsorflow命名空间与变量管理参数reuse
一.TensorFlow中变量管理reuse参数的使用 1.TensorFlow用于变量管理的函数主要有两个: (1)tf.get_variable:用于创建或获取变量的值 (2)tf.varia ...
- 【C#设计模式1】单例模式
一.引言 最近在设计模式的一些内容,主要的参考书籍是<Head First 设计模式>,同时在学习过程中也查看了很多博客园中关于设计模式的一些文章的,在这里记录下我的一些学习笔记,一是为了 ...
- Redis源码解析
一.src/server.c 中的redisCommandTable列出的所有redis支持的命令,其中字符串命令包括从get到mget:列表命令从rpush到rpoplpush:集合命令包括从sad ...
- 最新 花椒直播java校招面经 (含整理过的面试题大全)
从6月到10月,经过4个月努力和坚持,自己有幸拿到了网易雷火.京东.去哪儿.花椒直播等10家互联网公司的校招Offer,因为某些自身原因最终选择了花椒直播.6.7月主要是做系统复习.项目复盘.Leet ...
- Memcached内存调优及建议
一.Memcached调优 目标: 提高内存命中率 减少内存浪费 增加内存重复利用率 问题: 存不满Chunk 内存数据大量堆积 slab不能被page整除 page不能被Chunk整除 方向: 调整 ...
- 电子防抖(EIS)无效的相关修改
[DESCRIPTION] 电子防抖(EIS)无效的相关修改 [SOLUTION] 电子防抖(EIS)无效,根据不同的版本,可以先查看是否已经做了相关修改.1. MT6580/MT6735平台请参考如 ...