go interface接口
一:接口概要
接口是一种重要的类型,他是一组确定的方法集合。
一个接口变量可以存储任何实现了接口方法的具体值。
一个重要的例子就是io.Reader和io.Writer
type Reader interface {
Read(p []byte) (n int, err error)
} type Writer interface {
Write(p []byte)(n int, err error)
}
如果一个方法实现了io.Reader或者io.Writer里的方法,那么它便实现了io.Reader 或 io.Writer 。 这就
意味着一个io.Reader 变量可以持有任何一个实现了Read方法的类型的值 [1]
例 1:
var r io.Reader
r = os.Stdin
os.Stdin 在 os 包中定义:
var (
Stdin = NewFile(uintptr(syscall.Stdin), "/dev/stdin")
Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout")
)
NewFile 返回的是一个 *File 结构体,在 os/types.go, File 结构体代码,里面是一个匿名的file结构体
// File represents an open file descriptor.
type File struct {
*file // os specific
}
file也是一个结构体,os/file_plan9.go
type file struct {
fd int
name string
dirinfo *dirInfo // nil unless directory being read
}
这个 File 结构体实现了 Read(p []byte) (n int, err error) 方法, 而这个刚好是接口 io.Reader 里的方法
所以os.Stdin 可以赋值给 io.Reader
例 2:
var r io.Reader
r = bufio.NewReader(r)
在包 bufio.go
// NewReader returns a new Reader whose buffer has the default size.
func NewReader(rd io.Reader) *Reader {
return NewReaderSize(rd, defaultBufSize)
}
func NewReaderSize(rd io.Reader, size int) *Reader {
// Is it already a Reader?
b, ok := rd.(*Reader)
if ok && len(b.buf) >= size {
return b
}
if size < minReadBufferSize {
size = minReadBufferSize
}
r := new(Reader)
r.reset(make([]byte, size), rd)
return r
}
2)上面[1]中下划线 接口变量可以持有任何一个实现了Read方法的类型的值,那么接口变量又是什么呢?
变量里是具体值和这个值类型
3)一个类型实现了 interface 中的所有方法,我们就说该类型实现了该 interface,
所以所有的类型都实现了 empty interface,因为任何类型至少有0个方法。
go中没有显示的关键字来实现interface,只需要实现interface包含的方法即可
二: 接口定义
interface类型定义
type interfaceNamer interface {
Method1(param_list) return_type
Method2(param_list) return_type
...
}
按照约定,只包含一个方法的)接口的名字由方法名加 [e]r 后缀组成,例如 Printer、Reader、Writer、Logger、Converter 等等。还有一些不常用的方式(当后缀 er 不合适时),比如 Recoverable,此时接口名以 able 结尾,或者以 I 开头(像 .NET 或 Java 中那样)
接口可以屏蔽内部细节,和具体的实现方法。只关注我需要做什么,而不关注怎么做
三:接口和方法,实现接口的方法
示例:
package main import (
"fmt"
) type Ager interface {
Get() int
Set(int)
} type Student struct {
Age int
} func (s Student) Get() int {
return s.Age
} func (s *Student) Set(age int) {
s.Age = age
} func funone(ager Ager) {
ager.Set()
fmt.Println(ager.Get())
} func main() {
//=== 第一部分 stu 可以作为一个变量传递给函数,因为它作为一个struct实现了接口里面的方法
stu := Student{}
funone(&stu)
//=== 第二部分 i 作为一个接口变量,它存储了实现了这个接口方法的类型的值
var i Ager
i = &stu
fmt.Println(i.Get())
}
在上面程序中,定义来一个名为Ager的 interface 接口,里面定义了2个方法Get() , Set(), 定义了一个 student 的结构体,并且结构体实现了 interface 里面的2个方法Get,Set,我们就说结构体实现了 这个接口
定义了一个 funcone 的函数,里面参数ager是一个interface类型(interface类型作为函数参数),那么实现了这个接口的任何变量都可以作为参数传递给 funcone 了, (在 main 函数中 第一部分注释)
interface变量存储了实现者变量的值 (main函数中的 第二部分注释),所以它又可以调用结构体的方法
一个类型实现了接口里的所有方法,那么这个类型就实现了这个接口
四:接口嵌套
一个接口可以包含一个或者多个其他接口
相当于直接将这些内嵌接口的方法加入到了外层接口中,相当于组合了方法
还是拿最典型的 Reader 和 Writer 接口
type Reader interface {
Read(p []byte) (n int, err error)
} type Writer interface {
Write(p []byte) (n int, err error)
} type ReadWriter interface {
Reader
Writer
}
如果一个类型既实现了 Reader 接口,也实现了Writer接口,那么它就自动实现了 ReadWriter 接口
接口和结构体的定义很相似,也可以完成嵌入接口的功能,嵌入的匿名的接口,可以自动的具备被嵌入的接口的方法
五: 空interface
interface{} 空interface,它能存储任意类型的值, 它相当于 c 系的 void * 类型
定义一个空接口
var i interface{}
s := "hello"
num :
i = s
i = num
空接口在打印包中的应用,它又是一个可变长参数 fmt/print.go
func Println(a ...interface{}) (n int, err error) {
return Fprintln(os.Stdout, a...)
}
六:类型断言
既然接口类型能够实现多种类型的值,那么我们应该有一种方式来检测这种动态类型的值,即运行时变量中存储的值的实际类型。 在执行过程中动态类型可能会有所不同,但是它总是可以分配给接口变量本身的类型。
那就是 类型断言
1):type-ok 形式
1.1:第一种
直接判断是否是某类型的变量 value,ok = element.(T), 这里value是变量的值,ok是bool类型, element必须是一个 interface 变量, T是断言的类型
1.2 第二种 简单形式:
value := element.(T)
示例:
package main import (
"fmt"
"math"
) type Square struct {
side float32
} type Circle struct {
radius float32
} type Shaper interface {
Area() float32
} func main() {
var area Shaper
sq1 := new(Square)
sq1.side = area = sq1
//is Square the type of area
if t, ok := area.(*Square); ok {
fmt.Printf("The type of area is: %T \n", t)
} if u, ok := area.(*Circle); ok {
fmt.Printf("The type of area is: %T \n", u)
} else {
fmt.Println("area does not cotain a variable of type Cicle")
}
//输出结果
// go run assert1.go
// The type of area is: *main.Square
// area does not cotain a variable of type Cicle } func (sq *Square) Area() float32 {
return sq.side * sq.side
} func (ci *Circle) Area() float32 {
return ci.radius * ci.radius * math.Pi
}
2):switch 形式
上面也可以用 switch的形式
switch t := area.(type) {
case *Square:
fmt.Printf("Type Square %T with value %v\n", t, t)
case *Circle:
fmt.Printf("Type Circle %T with value %v\n", t, t)
case nil:
fmt.Printf("nil value: nothing to check?\n")
default:
fmt.Printf("Unexpected type %T\n", t)
}
参考:
1. http://wiki.jikexueyuan.com/project/the-way-to-go/11.4.html
2. https://research.swtch.com/interfaces
3. https://blog.golang.org/laws-of-reflection
go interface接口的更多相关文章
- as3.0 interface接口使用方法
[转]as3.0 interface接口使用方法 AS在2.0的时候就支持接口了 接口能够让你的程序更具扩展性和灵活性,打个例如 比方你定义了一个方法 代码: public function aMet ...
- interface接口
当一个抽象类中的方法都是抽象的时候,这时可以将该抽象类用另一种形式定义和表示,就是接口 interface. 定义接口使用的关键字不是class,是interface.接口中常见的成员: 这些成员都有 ...
- golang面向对象和interface接口
一. golang面向对象介绍 1.golang也支持面向对象编程,但是和传统的面向对象编程有区别,并不是纯粹的面向对象语言.2.golang没有类(class),golang语言的结合体(struc ...
- Golang 入门系列(四)如何理解interface接口
前面讲了很多Go 语言的基础知识,包括go环境的安装,go语言的语法等,感兴趣的朋友,可以先看看之前的文章.https://www.cnblogs.com/zhangweizhong/category ...
- java interface接口的传值方法
A 类 package interface_test; public class A { private IPresenter ip; public A(IPresenter ip) { this.i ...
- JAVA 构造器, extends[继承], implements[实现], Interface[接口], reflect[反射], clone[克隆], final, static, abstrac
记录一下: 构造器[构造函数]: 在java中如果用户编写类的时候没有提供构造函数,那么编译器会自动提供一个默认构造函数.它会把所有的实例字段设置为默认值:所有的数字变量初始化为0;所有的布尔变量设置 ...
- 011-对象——interface接口说明与使用方式实例
<?php /** interface接口说明与使用方式实例 * * 接口里面的方法全是抽象方法,没有实体的方法.这样的类我们就叫做接口.定义的时候用Interface定义.实现接口时用impl ...
- Java Interface接口
Java 中接口概念 接口可以理解为一种特殊的 类,由 全局常量 和 公共的抽象方法 所组成. 类是一种具体实现体,而接口定义了某一批类所需要遵循的规范,接口不关心这些类的内部数据, 也不关心这些类里 ...
- Golang基础(8):go interface接口
一:接口概要 接口是一种重要的类型,他是一组确定的方法集合. 一个接口变量可以存储任何实现了接口方法的具体值.一个重要的例子就是io.Reader和io.Writer type Reader inte ...
随机推荐
- Python第四天 流程控制 if else条件判断 for循环 while循环
Python第四天 流程控制 if else条件判断 for循环 while循环 目录 Pycharm使用技巧(转载) Python第一天 安装 shell 文件 Python第二天 ...
- mmz-asio4delphi死链接的解决办法
最近一段时间,因为忙于网络的项目,特意到网上找了些例子,特意花时间研究了一下马敏钊写的 mmz-asio4delphi 感觉很好用,不过深入研究之后,发现一个问题. 马大的这个代码,会产生死链接. ...
- Java 集合系列(三)—— LinkedList
以脑图的形式来展示Java集合知识,让零碎知识点形成体系 LinkedList LinkedList是一种可以在任何位置进行高效地插入和删除操作的有序序列. 它的最基本存储结构是一个节点:每 ...
- HO6 Condo Insurance Policy
The HO6 insurance Policy is the most common type of policy used to insure town homes and condos in t ...
- 英语口语练习系列-C08-考试
<蒹葭>-诗经 蒹葭苍苍,白露为霜.所谓伊人,在水一方.溯洄从之,道阻且长.溯游从之,宛在水中央. 蒹葭萋萋,白露未晞.所谓伊人,在水之湄.溯洄从之,道阻且跻.溯游从之,宛在水中坻. 蒹葭 ...
- Linux systemtap定位系统IO资源使用情况(ok)
一.systemtap介绍 SystemTap是一个强大的调试工具,是监控和跟踪运行中的Linux 内核的操作的动态方法,确切的说应该是一门调试语言,因为它有自己的语法,也有解析.编译.运行等过程(准 ...
- SoapUI 学习总结-01 环境配置
遇到的问题 1,怎么SoapUI的Request URL不支持大写怎么办? 问题:在SoapUI的Request URL中,每次输入的URL中含有的大写字母会自动转换为小写字母,导致请求不了对应的地址 ...
- 基于 HTML5 WebGL 的地铁站 3D 可视化系统
前言 工业互联网,物联网,可视化等名词在我们现在信息化的大背景下已经是耳熟能详,日常生活的交通,出行,吃穿等可能都可以用信息化的方式来为我们表达,在传统的可视化监控领域,一般都是基于 Web SCAD ...
- 用 C# 编写 C# 编译器,先有鸡还是先有蛋?
前段时间翻译了一篇文章 微软是如何重写 C# 编译器并使它开源的,文章讲了微软用 C# 重写 C# 编译器的坎坷路,引发了一些童鞋的思考:用 C# 编写 C# 编译器(Roslyn),那么 C# 编译 ...
- Jquery密码强度校验
function passValidate(){ var password=$password.val().trim() if(password===""){ $mima.addC ...