Go 接口

接口概览

接口大概理解

接口类型是队其他类型行为的概括与抽象

接口类型中,包含函数声明,但没有数据变量
接口的作用通过使用接口,可以写出更加灵活和通用的函数,这些函数不用绑定在一个特定的类型实现上
Go 接口特征

很多面向对象的语言都有接口这个概念,Go 语言的接口的独特之处在于,Go 接口是 "隐式实现"

也就是说,对于一个具体的类型 T ,无须声明类型 T 实现了哪些接口,只要提供接口所必需的方法即可

解释 :没有具体的语法,显式地表明一个具体类实现(继承)了某个接口;只要这个具体类实现(重写)了某个接口中的函数,那么这个具体类就是实现了该接口

这种接口的 "隐式实现" ,可以无须改变具体类的实现,就可以为具体类创建新的接口(功能),对于那些不能修改包的类型,这一点特别有用

什么是接口

具体类型

(i).  之前介绍的都是具体类型

(ii). 具体类型指定了所含数据的精确布局,还暴露了基于数据精确布局的内部操作

比如数值有算术操作,对于 slice 类型有索引 、append 、range 等操作

(iii). 具体类型还能通过新增方法来提供额外的能力

总之,如果知道了一个具体类型的数据,就精确地知道了该类型是什么以及能干什么

接口

Go 语言中,还有另外一种类型称为 "接口类型"

(i). "接口" 是一种 "抽象类型" 

(ii). 接口没有暴露所含数据的布局或者内部结构,也没有对于数据的操作,接口所提供的只是一些方法

(iii). 如果得到一个接口类型的值,则无法知道它是什么,只知道该接口值能做什么

说的直白一点,接口就是只包含函数声明的类,而且没有成员数据

示例

下面使用两个类似的函数,实现字符串的格式化 :fmt.Printf 和 fmt.Sprintf

fmt.Printf 把结果发送到标准输出(标准输出其实就是一个文件)

fmt.Sprintf 把结果以 string 类型返回

格式化是这两个函数中最复杂的部分,如果仅仅因为两个函数在输出方式上的轻微差异,就需要把格式化部分在。两个函数中重复实现一遍,那就太糟糕了;

幸运的是,通过接口机制可以解决这个问题;

其实,两个函数都封装了第三个函数 fmt.Fprintf ,而这个函数对结果实际输出到哪里毫不关心

package fmt

func Fprintf( w io.Writer,format string,args  ...interface{} )  ( int,error )

func Printf( format string,args  ...interface{} )  ( int,error ) {

        return Fprintf(os.Stdout ,format ,args...)

}

func Sprintf( format string,args  ...interface{} )  string {

        var  buf  bytes.Buffer

        Fprintf(&buf ,format ,args...)

        return buf.String()

}

说明

(i).   Fprintf 的前缀  F  指文件,表示格式化的输出会写入第一个实参所指代的文件

(ii).  对于 Printf ,第一个实参就是 os.Stdout ,它属于 *os.File 类型

(iii). 对于 Sprintf ,尽管第一个实参不是文件,但第一个实参模拟了一个文件 :

      &buf 就是一个指向内存缓冲区的指针,与文件类似,该缓冲区可以写入多个字节

(iv). 其实,Fprintf 的第一个形参也不是文件类型,而是 io.Writer 接口类型,其声明如下:

package  io

// Writer 接口封装了基础的写入方法

type  Writer  interface {

        // Write 从 p 向底层数据流写入 len(p) 个字节的数据

        // 返回实际写入的字节数 ( 0 <= n <= len(p) )

        // 如果没有写完,那么会返回遇到的错误

        // 在 Write 返回 n < len(p) 时,err 必须为非 nil

        // Write 不允许修改 p 的数据,即使是临时修改

        // 

        // 实现时不允许残留 p 的引用

        Write( p  []byte )  ( n int ,err  error )

}

io.Writer 接口定义了 Fprintf 和调用者之间的约定:

在使用函数 Fprintf 时,给到的第一个实参类型应该实现了接口 io.Writer

一方面,这个约定,要求调用者提供的具体类型(比如 *os.File 或 *bytes.Buffer)包含一个与其(接口中的方法签名)签名和行为一致的 Write 方法

签名一致,就是说,具体类型中,也有一个如下的,完全一样的方法

        Write(p []byte) (n int , err error )

行为一致,就是说,Write 从 p 向底层数据流写入 len(p) 个字节的数据,这里的底层数据流是数据的终点,这个终点相当于具体类型的一个成员;也就是说,方法 Write 会把数据写入具体类型中,而这个数据来源就是格式化字符串

另一方面,这个约定保证了 Fprintf 能使用任何满足 io.Writer 接口的参数;

Fprintf 只需要能调用参数(具体类型)的 Write 函数,无须假设 Write 写入的是一个文件还是一段内存(只要能写入数据即可

因为 fmt.Fprintf 仅依赖于 io.Writer 接口所约定的方法,对参数的具体类型没有要求,所以我们可以用任何满足(实现)io.Writer 接口的具体类型作为 fmt.Fprintf 的第一个实参

这种可以把一种类型替换为满足同一接口的另一种类型的特性,称为 "可取代性" ,这也是面向对象语言的典型特征

代码测试

创建一个新类型来测试一下这个特性。如下所示的 *ByteCounter 类型的 Write 方法仅仅统计传入数据的字节数,然后就不管那些数据了

(下面的代码中出现的类型转换是为了让 len(p) 和 *c 满足 += 操作)

type  ByteCounter  int

func (c *ByteCounter) Write(p []byte) (int,error) {

    *c += ByteCounter(len(p))    // 转换 int 为 ByteCounter 类型

    return len(p) ,nil

}

因为 *ByteCounter 满足 io.Writer 接口的约定,所以能在 Fprintf 中使用 ByteCounter ,Fprintf 察觉不到这种类型差异,ByteCounter 也能正确地累积格式化后结果的长度

var  c  ByteCounter

c.Write([]byte("hello"))

fmt.Println(c)    //  "5",= len("hello")

c = 0    // 重置计数器

var name = "Dolly"

fmt.Fprintf(&c,"hello,%s",name)

fmt.Println(c)    // "12",= len("hello,Dolly")

除了 io.Writer 之外,fmt 包还有一个重要的接口

Fprintf 和 Fprintln 提供了一个让类型控制如何输出自己的机制

给 Celsius 类型定义了一个 String 方法,这样可以输出 "100℃" 这样的结果;

给 *IntSet 类型加了一个 String 方法,这样可以输出类似 "{1  2  3}" 的传统集合表示形式

定义一个 String 方法就可以让类型满足这个广泛使用的接口 fmt.Stringer :

package  fmt

// 在字符串格式化时如果需要一个字符串

// 那么就调用这个方法来把当前值转换为字符串

// Print 这种不带格式化参数的输出方式也是调用这个方法

type  Stringer  interface {

        String()  string

}

接口类型(声明)

接口是隐式实现

    一个接口类型定义了一套方法,如果一个具体类型要实现该接口,那么必须实现接口类型定义中的所有方法

声明接口的几种方式

前提说明:

io.Writer 是一个广泛使用的接口,负责所有可以写入字节的类型的抽象,包括文件 、内存缓冲区 、网络连接 、HTTP 客户端 、打包器(archiver)、散列器(hasher)等;

io 包还定义了很多有用的接口;

Reader 就抽象了所有可以读取字节的类型,Closer 抽象了所有可以关闭的类型,比如文件或者网络连接

注意 :Go 语言的单方法接口的命名约定

说明 :字节流的最终目的地,位于具体类型中,接口是具体类型的抽象或者说概括

基础接口声明

package io
type Reader interface {Read(p []byte) (n int, err error)
}type Closer interface {Close() error
}

方式一(组合接口)

可以通过组合已有接口得到新接口;

下面这种声明接口的方式,称为 "嵌入式接口"

与嵌入式结构类似,可以直接使用一个接口,而不用逐一写出这个接口包含的方法

type ReadWriter interface {ReaderWriter
}type ReadWriteCloser interface {ReaderWriterCloser
}

方式二(组合方法)

尽管不够简洁,但是可以不用嵌入式来声明 io.ReadWriter

type ReadWriter interface {Read(p []byte) (n int, err error)Write(p []byte) (n int, err error)
}

方式三(组合接口、方法)

可以混合使用两种方式

type ReadWriter interface {Read(p []byte) (n int, err error)Writer
}

总结:

三种声明的效果都是一样的;

方法定义的顺序也是没有影响的,真正有意义的只有接口的方法集合

隐式实现一个接口类型定义了一套方法,如果一个具体类型要实现该接口,那么必须实现接口类型定义中的所有方法
声明接口的几种方式
前提说明

io.Writer 是一个广泛使用的接口,负责所有可以写入字节的类型的抽象,包括文件 、内存缓冲区 、网络连接 、HTTP 客户端 、打包器(archiver)、散列器(hasher)等;

io 包还定义了很多有用的接口;

Reader 就抽象了所有可以读取字节的类型,Closer 抽象了所有可以关闭的类型,比如文件或者网络连接

注意 :Go 语言的单方法接口的命名约定

说明 :字节流的最终目的地,位于具体类型中,接口是具体类型的抽象或者说概括

基础接口声明

package io

type Reader interface {

        Read(p []byte)  ( n  int ,err error )

}

type Closer interface {

        Close()  error

}

方式一

(组合接口)

另外,还可以通过组合已有接口得到新接口

type  ReadWriter interface {

        Reader

        Writer

}

type ReadWriteCloser interface {

        Reader

        Writer

        Closer

}

上面这种声明接口的方式,称为 "嵌入式接口"

与嵌入式结构类似,可以直接使用一个接口,而不用逐一写出这个接口包含的方法

方式二

(组合方法)

如下所示,尽管不够简洁,但是可以不用嵌入式来声明 io.ReadWriter

type ReadWriter interface {

        Read(p [ ]byte)  ( n int ,err error )

        Write(p [ ]byte)  (n int ,err error)

}

方式三

(组合接口、方法)

也可以混合使用两种方式

type ReadWriter interface {

        Read(p [ ]byte)  ( n int ,err error )

        Writer

}

三种声明的效果都是一样的;

方法定义的顺序也是没有影响的,真正有意义的只有接口的方法集合

接口实现

示例:使用 flag.Value 来解析参数

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/646608.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

验厂的类型的流程

【验厂的类型的流程】 在全球贸易一体化的进程中&#xff0c;验厂已经成为出口外贸企业真正与世界接轨的一道门槛&#xff0c;并且通过近几年的不断发展&#xff0c;验厂也逐渐为企业所熟知和充分重视。 如何正确理解验厂标准&#xff0c;实施有效的方案&#xff0c;满足验厂的…

PID控制算法,带C语言源码实现

1 PID简介 PID即&#xff1a;Proportional&#xff08;比例&#xff09;、Integral&#xff08;积分&#xff09;、Differential&#xff08;微分&#xff09;的缩写。PID控制算法是结合比例、积分和微分三种环节于一体的控制算法。PID算法是连续系统中技术最为成熟、应用最为…

面向对象和面向过程:C语言中的两种编程范式

C语言是一种结构化的编程语言&#xff0c;它支持两种不同的编程范式&#xff1a;面向对象和面向过程。编程范式是一种编程思想或风格&#xff0c;它决定了程序的组织和设计方式。本文将探讨面向对象和面向过程在C语言中的定义、特点、优缺点以及应用场景&#xff0c;并给出一些…

gitlab runner 安装、注册、配置、使用(Docker部署)

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

SQL 系列教程(一)

目录 SQL 简介 SQL 是什么 SQL 能做什么 SQL 语法 数据库表 SQL 语句 注意事项 SQL 语句后面的分号 一些最重要的 SQL 命令 SQL SELECT 语句 SQL SELECT 语句 演示数据库 SELECT Column 实例 SELECT * 实例 SQL SELECT DISTINCT 语句 SQL SELECT DISTINCT 语句…

【工具使用-Everything】everything只能搜到文件夹,无法搜到文件

一&#xff0c;问题现象 everything搜索时&#xff0c;只能搜索到文件夹&#xff0c;无法搜索到文件夹下的文件。 二&#xff0c;问题原因 everything搜索设置问题&#xff0c;设置为"文件夹"导致 三&#xff0c;解决方法 将搜索选项设置为“所有”即可&#x…

5 新增课程

5.1 需求分析 5.1.1 业务流程 根据前边对内容管理模块的数据模型分析&#xff0c;课程相关的信息有&#xff1a;课程基本信息、课程营销信息、课程图片信息、课程计划、课程师资信息&#xff0c;所以新增一门课程需要完成这几部分信息的填写。 以下是业务流程&#xff1a; …

全链路压测:提升业务可靠性和可用性

全链路压测是一种全面评估系统性能和稳定性的测试方法&#xff0c;通过模拟真实用户场景和流程来验证整个应用系统在高负载情况下的表现。全链路压测的主要作用涵盖了多个方面&#xff1a; 性能评估与优化&#xff1a; 全链路压测可以全面评估系统在高负载下的性能表现&#xf…

代码评审——随机数Random问题

问题描述&#xff1a; 为了获取唯一值&#xff0c;经常会依赖产生随机数来保证唯一性。在获取随机数时&#xff0c;如果使用错误的方法&#xff0c;会比较低效。 可以参考以下代码&#xff1a; public static String geneRundomNo(){Random rnew Random();int numr.nextInt(…

day31_CSS

今日内容 CSS概述引入方式 (where)选择器(how)属性(how) 1 CSS介绍 层叠样式表&#xff08;cascading style sheet&#xff09; CSS 用来美化HTML页面,可以让页面更好看,还可以布局页面. 好处 美化页面,布局页面使用外部css文件,可以实现样式文件和html文件分离,便于维护使用外…

再学jQuery

添加链接描述 jQuery源码采用模块化的设计&#xff0c;将不同功能的代码模块化&#xff0c;并通过jQuery.fn扩展原型链&#xff0c;使得可以灵活地使用各种功能和方法。这样的设计使得代码结构清晰&#xff0c;易于维护和扩展。jQuery源码中考虑了跨浏览器兼容性&#xff0c;通…

苹果眼镜(Vision Pro)的开发者指南(1)

一、用到的底层核心框架: SwiftUI:无论开发者是要创建窗口、体积还是空间体验,SwiftUI 都是构建新的 visionOS 应用程序或将现有 iPadOS 或 iOS 应用程序引入平台的最佳方式。凭借全新的 3D 功能以及对深度、手势、效果和沉浸式场景类型的支持,SwiftUI 可以帮助你为 Vision…

5.ROC-AUC机器学习模型性能的常用的评估指标

最近回顾机器学习基础知识部分的时候&#xff0c;看到了用于评估机器学习模型性能的ROC曲线。再次记录一下&#xff0c;想起之前学习的时候的茫然&#xff0c;希望这次可以更加清晰的了解这一指标。上课的时候听老师提起过&#xff0c;当时没有认真去看&#xff0c;所以这次可以…

SpeechGPT-Gen;使用Agents编辑图像;多模态扩散模型图像生成

本文首发于公众号&#xff1a;机器感知 SpeechGPT-Gen&#xff1b;使用Agents编辑图像&#xff1b;多模态扩散模型图像生成&#xff1b; CCA: Collaborative Competitive Agents for Image Editing This paper presents a novel generative model, Collaborative Competitive…

多流转换 (分流,合流,基于时间的合流——双流联结 )

目录 一&#xff0c;分流 1.实现分流 2.使用侧输出流 二&#xff0c;合流 1&#xff0c;联合 2&#xff0c;连接 三&#xff0c;基于时间的合流——双流联结 1&#xff0c;窗口联结 1.1 窗口联结的调用 1.2 窗口联结的处理流程 2&#xff0c;间隔联结 2.1 间隔联…

<网络安全>《2 国内主要企业网络安全公司概览(二)》

4 北京天融信科技有限公司(简称天融信) 信息内容LOGO成立日期创始于1995年总部北京市海淀区上地东路1号院3号楼北侧301室背景民营企业是否上市天融信[002212]A股市值99亿主要产品网络安全大数据云服务员工规模6000多人简介天融信科技集团&#xff08;证券代码&#xff1a;0022…

# Java NIO(一)FileChannel

Java NIO 1.BIO与NIO的区别 BIO为阻塞IO&#xff0c;NIO为非阻塞IO。 BIONIOJAVA1.4之前Java 1.4之后面向流&#xff1a;以byte为单位处理数据面向块&#xff1a;以块为单位处理数据同步阻塞同步非阻塞无选择器&#xff08;Selector&#xff09; 1.1NIO的核心组成部分 Cha…

书生·浦语大模型实战营-学习笔记6

目录 OpenCompass大模型测评1. 关于评测1.1 为什么要评测&#xff1f;1.2 需要评测什么&#xff1f;1.3 如何评测&#xff1f;1.3.1 客观评测1.3.2 主观评测1.3.3 提示词工程评测 2. 介绍OpenCompass工具3. 实战演示 OpenCompass大模型测评 1. 关于评测 1.1 为什么要评测&#…

人工智能系列 :与机器共生的未来

大家好&#xff0c;身处一个日新月异的时代&#xff0c;科技的浪潮汹涌而至&#xff0c;将人们推向未知的前方&#xff0c;一个充满人工智能与机器的世界。 这个未知的境地&#xff0c;或许令人心生恐慌&#xff0c;因为它的庞大未知性仿佛一团迷雾&#xff0c;模糊了大家的视…

Unity Mask合批情况验证

1.首先是两个Mask完全重合的情况下 每张图片使用的image都来自同一个图集 发现彼此之间是没有合批的&#xff0c;但是每个Mask内部是实现了合批的 经过计算此种情况的visiableList&#xff1a;mask1&#xff0c;IM1&#xff0c;IM2&#xff0c;mask2&#xff0c;IM3&#xf…