本文来自: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 接口使用的更多相关文章

  1. App开发:模拟服务器数据接口 - MockApi

    为了方便app开发过程中,不受服务器接口的限制,便于客户端功能的快速测试,可以在客户端实现一个模拟服务器数据接口的MockApi模块.本篇文章就尝试为使用gradle的android项目设计实现Moc ...

  2. 干货来袭-整套完整安全的API接口解决方案

    在各种手机APP泛滥的现在,背后都有同样泛滥的API接口在支撑,其中鱼龙混杂,直接裸奔的WEB API大量存在,安全性令人堪优 在以前WEB API概念没有很普及的时候,都采用自已定义的接口和结构,对 ...

  3. 12306官方火车票Api接口

    2017,现在已进入春运期间,真的是一票难求,深有体会.各种购票抢票软件应运而生,也有购买加速包提高抢票几率,可以理解为变相的黄牛.对于技术人员,虽然写一个抢票软件还是比较难的,但是还是简单看看123 ...

  4. Java基础Map接口+Collections工具类

    1.Map中我们主要讲两个接口 HashMap  与   LinkedHashMap (1)其中LinkedHashMap是有序的  怎么存怎么取出来 我们讲一下Map的增删改查功能: /* * Ma ...

  5. Java基础Map接口+Collections

    1.Map中我们主要讲两个接口 HashMap  与   LinkedHashMap (1)其中LinkedHashMap是有序的  怎么存怎么取出来 我们讲一下Map的增删改查功能: /* * Ma ...

  6. java基础_集合List与Set接口

    List接口继承了Collection的方法  当然也有自己特有的方法向指定位置添加元素   add(索引,添加的元素); 移除指定索引的元素   remove(索引) 修改指定索引的元素   set ...

  7. 【WCF】自定义错误处理(IErrorHandler接口的用法)

    当被调用的服务操作发生异常时,可以直接把异常的原始内容传回给客户端.在WCF中,服务器传回客户端的异常,通常会使用 FaultException,该异常由这么几个东东组成: 1.Action:在服务调 ...

  8. PHP以接口方式实现多重继承(完全模拟)--学习笔记

     1.UML类图: 2.PHP代码: <?php /** * Created by PhpStorm. * User: andy * Date: 16-11-23 * Time: 下午7:57 ...

  9. 【微框架】Maven +SpringBoot 集成 阿里大鱼 短信接口详解与Demo

    Maven+springboot+阿里大于短信验证服务 纠结点:Maven库没有sdk,需要解决 Maven打包找不到相关类,需要解决 ps:最近好久没有写点东西了,项目太紧,今天来一篇 一.本文简介 ...

  10. 【接口开发】浅谈 SOAP Webserver 与 Restful Webserver 区别

    接口,强大,简单,交互,跨越平台 下面简单阐述这两大接口思想 一 REST: REST是一种架构风格,其核心是面向资源,REST专门针对网络应用设计和开发方式,以降低开发的复杂性,提高系统的可伸缩性. ...

随机推荐

  1. PAT 甲级 1043 Is It a Binary Search Tree (25 分)(链表建树前序后序遍历)*不会用链表建树 *看不懂题

    1043 Is It a Binary Search Tree (25 分)   A Binary Search Tree (BST) is recursively defined as a bina ...

  2. Laravel 项目开发环境配置

    1.首先安装Laravel 依赖管理包工具 Composer (前提是本地装好了PHP  php -v) php -r "copy('https://install.phpcomposer. ...

  3. php-fpm优化参数介绍

    1.php-fpm优化参数介绍他们分别是:pm.pm.max_children.pm.start_servers.pm.min_spare_servers.pm.max_spare_servers. ...

  4. jenkins的pipeline拉取指定分支的代码

    脚本示例 pipeline { agent any options { durabilityHint 'PERFORMANCE_OPTIMIZED' timeout(time:5, unit: 'MI ...

  5. 修改iPhone5s crash 问题

  6. Flask框架(2)--编写简单的用户注册--登录场景

    为了更好的理解web前后端的工作业务逻辑:本笔记记录用flask框架编写的一个最初级的代码实现简单的用户注册,登录场景: 初次进入首页,提示--游客,欢迎参观,有登录和注册选项, 登录成功后的用户,会 ...

  7. 删除Excel表格中一堆英文中的汉字

    昨天需要处理一个Excel文件,删除一堆英文里的汉字,开始搜了下方法,没找到,然后手动一个多小时,弄了一半吧也就,结果电脑卡了,忘了保存,就白做了...不知道为啥这次没有自动保存,所以,重要的事说三遍 ...

  8. leetcode1277 Count Square Submatrices with All Ones

    思路: 使用动态规划,dp[i][j]表示以(i, j)作为右下角的最大的全1矩阵的边长. 实现: class Solution { public: int countSquares(vector&l ...

  9. 基本 Java Bean

    <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://mave ...

  10. python代码注释 - python基础入门(4)

    在 python改变世界,从hello world开始 中我们已经完成了第一个python程序,代码是有了,关键是好像好不知道写的啥玩意? 一.什么是代码注释 代码注释就是给一段代码加上说明,表明这段 ...