当前位置: 首页 > news >正文

Go语言程序设计-第7章--接口

Go语言程序设计-第7章–接口

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

Go 语言的接口的独特之处在于它是隐式实现。对于一个具体的类型,无须声明它实现了哪些接口,只要提供接口所必须实现的方法即可。

7.1 接口即约定

7.2 接口类型

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

组合已有接口得到新的接口。

  • 嵌入式声明
type ReadWriter interface {ReaderWriter
}
  • 直接声明
type ReadWriter interface {Read(p []byte) (n int, err error)Close() error
}
  • 混合声明
type ReadWriter interface {Read(p []byte) (n int, err error)Writer
}

7.3 实现接口

接口的实现规则很简单,仅当一个表达式实现了一个接口时,这个表达式才可以赋值给接口。

var w io.Writer
w = os.Stdout // OK: *os.File 有 Writable 方法
w = new(bytes.Buffer) // OK: * bytes.Buffer 有 Writable 方法
w = time.Second // 编译错误: time.Duration 没有 Writable 方法=

如果方法的接收者是一个指针类型,就不可以从一个无地址的对象上调用该方法,如:

type IntSet struct {}
func (*IntSet) String() stringvar _ = IntSet{}.String() // 编译错误:String 方法需要 *IntSet 接收者

可以从一个 IntSet 变量上调用此方法

var s IntSet
var _ = s.String() // OK: s 是一个变量,&s 有 String 方法。

因为只有 *IntSet 有 String 方法,所以也只有 *IntSet 实现了 fmt.Stringer 接口。

var _ fmt.Stringer = &s // OK
var _ fmt.Stringer = s // 编译错误: IntSet 缺少 String 方法。

可以把任何数据赋值给空接口类型。

var any interface{} // 空接口类型
any = true
any = 12.34
any = "hello"
any = map[string]int {"one":1}
fmt.Println(any)

判断是否实现接口只需要比较具体类型和接口类型的方法,所以没有必要在具体类型的定义中声明这种关系。

非空的接口类型(如 io.Writer)通常由一个指针类型来实现,特别是当接口类型的一个或多个方法暗示会修改接收者的情形。一个指向结构的指针才是最常见的方法接收者。

7.4 使用 flat.Value 来解析参数

tempflag.go

package mainimport ("flag""fmt"
)type Celsius float64
type Fahrenheit float64func CToF(c Celsius) Fahrenheit { return Fahrenheit(c*9.0/5.0 + 32.0) }
func FToC(f Fahrenheit) Celsius { return Celsius((f - 32.0) * 5.0 / 9.0) }func (c Celsius) String() string { return fmt.Sprintf("%g°C", c) }/*
//!+flagvalue
package flag// Value is the interface to the value stored in a flag.
type Value interface {String() stringSet(string) error
}
//!-flagvalue
*///!+celsiusFlag
// *celsiusFlag satisfies the flag.Value interface.
type celsiusFlag struct{ Celsius }func (f *celsiusFlag) Set(s string) error {var unit stringvar value float64fmt.Sscanf(s, "%f%s", &value, &unit) // no error check neededswitch unit {case "C", "°C":f.Celsius = Celsius(value)return nilcase "F", "°F":f.Celsius = FToC(Fahrenheit(value))return nil}return fmt.Errorf("invalid temperature %q", s)
}//!-celsiusFlag//!+CelsiusFlag// CelsiusFlag defines a Celsius flag with the specified name,
// default value, and usage, and returns the address of the flag variable.
// The flag argument must have a quantity and a unit, e.g., "100C".
func CelsiusFlag(name string, value Celsius, usage string) *Celsius {f := celsiusFlag{value}flag.CommandLine.Var(&f, name, usage)return &f.Celsius
}
var temp = CelsiusFlag("temp", 20.0, "the temperature")
func main() {flag.Parse()fmt.Println(*temp)
}

7.5 接口值

一个接口类型的值(简称接口值)其实有两个部分:一个具体类型和该类型的一个值。二者称为接口的动态类型和动态值。

类型描述符来提供每个类型的具体信息,比如它的名字和方法。对于一个接口值,类型部分就用对应的类型描述符来表述。

如下四个语句中,变量 w 有三个不同的值(最初和最后是同一个值,都是 nil)

var w io.Writer
w = os.Stdout
w = new(bytes.Buffer)
w = nil

每个语句后 w 的值和相关的动态行为。第一个语句声明了 w: var w io.Writer
在 Go 语言中,变量总是初始化为一个特定的值,接口也不例外。接口的零值就是把它的动态类型和值都设置为 nil

一个接口值是否是 nil 取决于它的动态类型,所以现在这是一个 nil 接口值。可以用 w == nil 或者 w != nil 来检测一个接口值是否是 nil

第二个语句把一个 *os.File 类型的值赋给了 w: w = os.Stdout
这次赋值把一个具体类型隐私转换为一个接口类型,它与对应的显式转换 io.Writer(os.Stdout) 等价。接口的动态类型会设置为指针类型 *os.File 的类型描述符,它的动态值会设置为 os.Stdout 的副本,即一个指向代表进程的标准输出的 os.File 类型的指针。

调用 w.Write([]byte(“hello”)) //
等价于 os.Stdout.Write([]byte("hello"))

接口值可以用 == 和 != 操作符来比较。

在比较两个接口值时,如果两个接口值的动态类型一致,但对应的动态值是不可比较的(如 slice),那么这个比较会导致宕机。

var w io.Writer
fmt.Printf("%T\n", w) // "<nil>"w = os.Stdout
fmt.Printf("%T\n", w) // "*os.File"w = new(bytes.Buffer)
fmt.Printf("%T\n", w) // "*bytes.Buffer"

注意:含有空指针的非空接口
一个接口值是否是 nil 取决于它的动态类型。

const debug = truefunc f(out io.Writer) {if out != nil {out.Write([]byte("done!\n"))}
}
func main() {var buf *bytes.Bufferif debug {buf = new(bytes.Buffer) // 启用输出收集}f(buf)
}

当 main 调用 f 时,把一个类型为*bytes.Buffer 的空指针赋给了 out 参数,所以 out 的动态类型是 *bytes.Buffer,动态值是 nil。但是判断 out != nil 判断的是它的动态类型,所以 out != nil 返回true。
调用 out.Write 时,不允许接收者为空。

正确方法:

var buf io.Writer
if debug {buf = new(bytes.Buffer)
}

7.6 使用 sort.Interface 来排序

package sort
type Interface interface {Len() intLess(i, j int) bool // i, j 是序列元素的下标Swap(i, j int)
}

要对序列排序,需要先确定一个实现了如上三个方法的类型,接着把 sort.Sort 函数应用到上面这类方法的实例上。

type StringSlice []string
func (p StringSlice) Len() int { return len(p)}
func (p StringSlice) Less(i, j int) bool {return p[i] < p[j]}
func (p StringSlice) Swap(i, j int) {p[i], p[j] = p[j], p[i]}
sort.Sort(StringSlice(names))

7.7 http.Handler 函数

package http
type Handler interface {ServeHTTP(w ResponseWriter, r *Request)
}func ListenAndServe(address string, h Handler) error

net/http 包提供了一个请求多工转发器 ServeMux。

下面的代码中,将 /list, price 这样的 URL 和对应的处理程序关联起来。

package mainimport ("fmt""log""net/http"
)func main() {db := database{"shoes": 50, "socks": 5}mux := http.NewServeMux()//!+mainmux.HandleFunc("/list", db.list)mux.HandleFunc("/price", db.price)//!-mainlog.Fatal(http.ListenAndServe("localhost:8000", mux))
}type database map[string]intfunc (db database) list(w http.ResponseWriter, req *http.Request) {for item, price := range db {fmt.Fprintf(w, "%s: $%d\n", item, price)}
}func (db database) price(w http.ResponseWriter, req *http.Request) {item := req.URL.Query().Get("item")if price, ok := db[item]; ok {fmt.Fprintf(w, "$%d\n", price)} else {w.WriteHeader(http.StatusNotFound) // 404fmt.Fprintf(w, "no such item: %q\n", item)}
}

7.8 error 接口

Error 是一个接口类型,包含返回错误消息的方法

type error interface {Error() string
}func New(text string) error { return &errorString{text}}type errorString struct {text string}func (e *errorString) Error() string { return e.Text }

直接调用 errors.New 比较罕见,一般使用 fmt.Errorf。

package jmtimport "errors"func Errorf(format string, args ...interface{}) error {return errors.New(Sprintf(format, args...))
}

7.10 断言类型

类型断言是一个作用在接口值上的操作,写出来类似 x.(T), 其中 x 是一个接口类型的表达式,而 T 是一个断言类型。类型断言会检查作为操作数的动态类型是否满足指定的断言类型。

if f, ok := w.(*os.File); ok {// 使用 f
}

7.11 使用断言类型来识别错误

os.PathError

type PathError struct {Op stringPath stringErr error
}func (e *PathError) Error() string {return e.Op + " " + ": " + e.Err.Error()
}

可以根据类型断言来检查错误的特定类型,这些类型包含的细节远远多于一个简单的字符串。

_, err := os.Open("/no/such/file")
fmt.Println(err)
fmt.Printf("%#v\n", err)

7.12 通过接口类型断言来查询特性

func writeString(w io.Writer, s string)(n int, err error) {type stringWriter interface {WritesString(string) (n int, err error)}if sw, ok := w.(StringWriter); ok {return sw.WriteString(s) // 避免了内存复制}return w.Write([]byte(s))
}

7.13 类型分支

类型分支与普通的分支语句类似,差别是操作数改为 x.(type).

switch x.(type) {case nil:  //case init, unit: //case bool: //
}

相关文章:

Go语言程序设计-第7章--接口

Go语言程序设计-第7章–接口 接口类型是对其他类型行为的概括与抽象。 Go 语言的接口的独特之处在于它是隐式实现。对于一个具体的类型&#xff0c;无须声明它实现了哪些接口&#xff0c;只要提供接口所必须实现的方法即可。 7.1 接口即约定 7.2 接口类型 package iotype …...

性能优化-OpenMP基础教程(二)

本文主要介绍OpenMP并行编程技术&#xff0c;编程模型、指令和函数的介绍、以及OpenMP实战的几个例子。希望给OpenMP并行编程者提供指导。 &#x1f3ac;个人简介&#xff1a;一个全栈工程师的升级之路&#xff01; &#x1f4cb;个人专栏&#xff1a;高性能&#xff08;HPC&am…...

让电脑变得更聪明——用python实现五子棋游戏

作为经典的棋类游戏&#xff0c;五子棋深受大众喜爱&#xff0c;但如果仅实现人与人的博弈&#xff0c;那程序很简单&#xff0c;如果要实现人机对战&#xff0c;教会计算机如何战胜人类&#xff0c;那就不是十分容易的事了。本文我们先从简单入手&#xff0c;完成五子棋游戏的…...

C#-接口

接口 (interface) 定义了一个可由类和结构实现的协定。接口可以包含方法、属性、事件和索引器。接口不提供它所定义的成员的实现 — 它仅指定实现该接口的类或结构必须提供的成员。 接口可支持多重继承。在下面的示例中,接口 IComboBox 同时从 ITextBox 和 IListBox 继承。 i…...

ASP.NET可视化流程设计器源码

源码介绍: ASP.NET可视化流程设计器源码已应用于众多大型企事业单位。拥有全浏览器兼容的可视化流程设计器、表单设计器、基于角色的权限管理等系统开发必须功能&#xff0c;大大为您节省开发时间&#xff0c;是您开发OA.CRM、HR等企事业各种应用管理系统和工作流系统的最佳基…...

景联文科技GPT教育题库:AI教育大模型的强大数据引擎

GPT-4发布后&#xff0c;美国奥数队总教练、卡耐基梅隆大学数学系教授罗博认为&#xff0c;这个几乎是用“刷题”方式喂大的AI教育大模型的到来&#xff0c;意味着人类的刷题时代即将退出历史舞台。 未来教育将更加注重学生的个性化需求和多元化发展&#xff0c;借助GPT和AI教育…...

PHP进阶-实现网站的QQ授权登录

授权登录是站点开发常见的应用场景&#xff0c;通过社交媒体一键授权可以跳过注册站点账户的繁琐操作。本文将讲解如何用PHP实现QQ授权登录。首先&#xff0c;我们需要申请QQ互联开发者账号获得APPID和密钥&#xff1b;接着&#xff0c;我们下载QQ官方SDK&#xff1a;PHP SDK v…...

字节跳动基础架构SRE-Copilot获得2023 CCF国际AIOps挑战赛冠军

近日&#xff0c;2023 CCF国际AIOps挑战赛决赛暨“大模型时代的AIOps”研讨会在北京成功举办&#xff0c;活动吸引了来自互联网、运营商、科研院所、高校、软硬件厂商等领域多名专家学者参与&#xff0c;为智能运维的前沿学术研究、落地生产实践打开了新思路。决赛中&#xff0…...

python moviepy 图文批量合成带字幕口播视频

最近在研究将图片和文本批量合成为带字幕口播视频 主要是基于python的moviepy库 from generator import audio, pics, subs, videodef main():texts_input examplepics_input example# 图片分辨率预处理pics.adjust(pics_input)# 文字转语音audio.text_to_audio(texts_inpu…...

【代码片段】Linux C++打印当前函数调用堆栈

在开发大型项目时&#xff0c;尤其是多线程情况下&#xff0c;一般无法使用断点调试&#xff0c;这时候将当前函数的调用堆栈打印出来是非常有必要和有效的问题排查手段。 这里记录一段Linux环境下&#xff0c;打印函数堆栈的代码。 void get_native_callstack(std::string &a…...

Linux程序、进程以及计划任务(第一部分)

目录 一、程序和进程 1、什么是程序&#xff1f; 2、什么是进程&#xff1f; 3、线程是什么&#xff1f; 4、如何查看是多线程还是单线程 5、进程结束的两种情况&#xff1a; 6、进程的状态 二、查看进程信息的相关命令 1、ps&#xff1a;查看静态的进程统计信息 2、…...

Oracle database 12cRAC异地恢复至单机

环境 rac 环境 byoradbrac Oracle12.1.0.2 系统版本&#xff1a;Red Hat Enterprise Linux Server release 6.5 软件版本&#xff1a;Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit byoradb1&#xff1a;172.17.38.44 byoradb2&#xff1a;172.17.38.4…...

【docker】linux部署docker

简介 首先我需要声明的是&#xff0c;我的系统是centos7&#xff0c;下载工具使用的是yum&#xff1b;在linux上部署docker&#xff0c;之前一直看的是这篇文章Linux之Docker部署&#xff0c;基本上功能方面也都可以使用&#xff0c;部署起来也是比较的简单。首先我先讲述这篇…...

【K8S 云原生】Pod资源限制、Pod容器健康检查(探针)

目录 一、docker的重启方式和K8S重启方式 1、Pod的重启方式&#xff1a; 2、docker的重启策略&#xff1a; 二、yaml文件快速生成&#xff1a; 三、pod的状态&#xff1a; 四、Pod的资源限制 1、限制的方式和种类 2、CPU的限制的格式&#xff1a; 五、K8S拉取镜像的策…...

Python从入门到网络爬虫(模块详解)

模块 我们知道&#xff0c;函数和类都是可以重复调用的代码块。在程序中使用位于不同文件的代码块的方法是&#xff1a;导入 (import) 该对象所在的模块 (mudule)。当程序变得越来越大时&#xff0c;将程序的不同部分根据不同分类方法保存在不同文件中通常会更加方便。 导入模…...

[大厂实践] 无停机迁移大规模关键流量(下)

在系统升级、迁移的过程中&#xff0c;如何验证系统逻辑、性能正确无误&#xff0c;是一个很大的挑战。这一系列介绍了Netflix通过重放流量测试解决这一挑战的实践。原文: Migrating Critical Traffic At Scale with No Downtime — Part 2 想象一下&#xff0c;你被心爱的Netf…...

VMware Workstation虚拟机CentOS 7.9 配置固定ip的步骤

VMware Workstation虚拟机CentOS7.9配置固定ip的步骤 编辑虚拟机 打开VMware Workstation。 选择要配置的虚拟机&#xff0c;但不要启动它。 点击“编辑虚拟机设置”&#xff08;Edit virtual machine settings&#xff09;。 选择“网络适配器”&#xff08;Network Adapter&…...

构建自己的私人GPT

创作不易&#xff0c;请大家多鼓励支持。 在现实生活中&#xff0c;很多人的资料是不愿意公布在互联网上的&#xff0c;但是我们又要使用人工智能的能力帮我们处理文件、做决策、执行命令那怎么办呢&#xff1f;于是我们构建自己或公司的私人GPT变得非常重要。 一、本地部署…...

EtherCAT主站SOEM -- 14 --Qt-Soem通过界面采集从站IO进行显示

EtherCAT主站SOEM -- 14 --Qt-Soem通过界面采集从站IO进行显示 一 mainwindow.c 文件函数:1.1 自定义PDO配置1.2 主站初始化二 motrorcontrol.c 文件三 allvalue.h 文件该文档修改记录:总结一 mainwindow.c 文件函数: 1.1 自定义PDO配置 int IO_setup(uint16 slave) {int...

线程安全、共享变量的可见性

Java中的线程安全问题 谈到线程安全问题&#xff0c;我们先说说什么是共享资源。所谓共享资源&#xff0c;就是说该资源被多个线程所持有或者说多个线程都可以去访问该资源。 线程安全问题是指当多个线程同时读写一个共享资源并且没有任何同步措施时&#xff0c;导致出现脏数…...

循环冗余码校验CRC码 算法步骤+详细实例计算

通信过程&#xff1a;&#xff08;白话解释&#xff09; 我们将原始待发送的消息称为 M M M&#xff0c;依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)&#xff08;意思就是 G &#xff08; x ) G&#xff08;x) G&#xff08;x) 是已知的&#xff09;&#xff0…...

Neo4j 集群管理:原理、技术与最佳实践深度解析

Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

GruntJS-前端自动化任务运行器从入门到实战

Grunt 完全指南&#xff1a;从入门到实战 一、Grunt 是什么&#xff1f; Grunt是一个基于 Node.js 的前端自动化任务运行器&#xff0c;主要用于自动化执行项目开发中重复性高的任务&#xff0c;例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...

免费PDF转图片工具

免费PDF转图片工具 一款简单易用的PDF转图片工具&#xff0c;可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件&#xff0c;也不需要在线上传文件&#xff0c;保护您的隐私。 工具截图 主要特点 &#x1f680; 快速转换&#xff1a;本地转换&#xff0c;无需等待上…...

Caliper 配置文件解析:fisco-bcos.json

config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...

WPF八大法则:告别模态窗口卡顿

⚙️ 核心问题&#xff1a;阻塞式模态窗口的缺陷 原始代码中ShowDialog()会阻塞UI线程&#xff0c;导致后续逻辑无法执行&#xff1a; var result modalWindow.ShowDialog(); // 线程阻塞 ProcessResult(result); // 必须等待窗口关闭根本问题&#xff1a…...

用递归算法解锁「子集」问题 —— LeetCode 78题解析

文章目录 一、题目介绍二、递归思路详解&#xff1a;从决策树开始理解三、解法一&#xff1a;二叉决策树 DFS四、解法二&#xff1a;组合式回溯写法&#xff08;推荐&#xff09;五、解法对比 递归算法是编程中一种非常强大且常见的思想&#xff0c;它能够优雅地解决很多复杂的…...

验证redis数据结构

一、功能验证 1.验证redis的数据结构&#xff08;如字符串、列表、哈希、集合、有序集合等&#xff09;是否按照预期工作。 2、常见的数据结构验证方法&#xff1a; ①字符串&#xff08;string&#xff09; 测试基本操作 set、get、incr、decr 验证字符串的长度和内容是否正…...

表单设计器拖拽对象时添加属性

背景&#xff1a;因为项目需要。自写设计器。遇到的坑在此记录 使用的拖拽组件时vuedraggable。下面放上局部示例截图。 坑1。draggable标签在拖拽时可以获取到被拖拽的对象属性定义 要使用 :clone, 而不是clone。我想应该是因为draggable标签比较特。另外在使用**:clone时要将…...

python可视化:俄乌战争时间线关键节点与深层原因

俄乌战争时间线可视化分析&#xff1a;关键节点与深层原因 俄乌战争是21世纪欧洲最具影响力的地缘政治冲突之一&#xff0c;自2022年2月爆发以来已持续超过3年。 本文将通过Python可视化工具&#xff0c;系统分析这场战争的时间线、关键节点及其背后的深层原因&#xff0c;全面…...