day2加餐 Go 接口型函数的使用场景
文章目录
- 问题
- 价值
- 使用场景
- 其他语言类似特性
问题
在 动手写分布式缓存 - GeeCache day2 单机并发缓存 这篇文章中,有一个接口型函数的实现:
// A Getter loads data for a key.
type Getter interface {Get(key string) ([]byte, error)
}// A GetterFunc implements Getter with a function.
type GetterFunc func(key string) ([]byte, error)// Get implements Getter interface function
func (f GetterFunc) Get(key string) ([]byte, error) {return f(key)
}
这里呢,定义了一个接口 Getter
,只包含一个方法 Get(key string) ([]byte, error)
,紧接着定义了一个函数类型 GetterFunc
,GetterFunc
参数和返回值与 Getter
中 Get
方法是一致的。而且 GetterFunc
还定义了 Get
方式,并在 Get
方法中调用自己,这样就实现了接口 Getter
。所以 GetterFunc 是一个实现了接口的函数类型,简称为接口型函数。
接口型函数只能应用于接口内部只定义了一个方法的情况
,例如接口 Getter
内部有且只有一个方法 Get
。既然只有一个方法,为什么还要多此一举,封装为一个接口呢?定义参数的时候,直接用 GetterFunc
这个函数类型不就好了,让用户直接传入一个函数作为参数,不更简单吗?
所以呢,接口型函数的价值什么?
价值
我们想象这么一个使用场景,GetFromSource
的作用是从某数据源获取结果,接口类型 Getter
是其中一个参数,代表某数据源:
func GetFromSource(getter Getter, key string) []byte {buf, err := getter.Get(key)if err == nil {return buf}return nil
}
我们可以有多种方式调用该函数:
方式一:GetterFunc 类型的函数作为参数
GetFromSource(GetterFunc(func(key string) ([]byte, error) {return []byte(key), nil
}), "hello")
支持匿名函数,也支持普通的函数:
func test(key string) ([]byte, error) {return []byte(key), nil
}func main() {GetFromSource(GetterFunc(test), "hello")
}
将 test
强制类型转换为 GetterFunc
,GetterFunc
实现了接口 Getter
,是一个合法参数。这种方式适用于逻辑较为简单的场景。
方式二:实现了 Getter 接口的结构体作为参数
type DB struct{ url string}func (db *DB) Query(sql string, args ...string) string {// ...return "hello"
}func (db *DB) Get(key string) ([]byte, error) {// ...v := db.Query("SELECT NAME FROM TABLE WHEN NAME= ?", key)return []byte(v), nil
}func main() {GetFromSource(new(DB), "hello")
}
DB
实现了接口 Getter
,也是一个合法参数。这种方式适用于逻辑较为复杂的场景,如果对数据库的操作需要很多信息,地址、用户名、密码,还有很多中间状态需要保持,比如超时、重连、加锁等等。这种情况下,更适合封装为一个结构体作为参数。
这样,既能够将普通的函数类型(需类型转换)作为参数,也可以将结构体作为参数,使用更为灵活,可读性也更好,这就是接口型函数的价值。
使用场景
这个特性在 groupcache
等大量的 Go
语言开源项目中被广泛使用,标准库中用得也不少,net/http
的 Handler
和 HandlerFunc
就是一个典型。
我们先看一下 Handler
的定义:
type Handler interface {ServeHTTP(ResponseWriter, *Request)
}
type HandlerFunc func(ResponseWriter, *Request)func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {f(w, r)
}
摘自 Go
语言源代码 net/http/server.go
我们可以 http.Handle
来映射请求路径和处理函数,Handle
的定义如下:
func Handle(pattern string, handler Handler)
第二个参数是即接口类型 Handler
,我们可以这么用。
func home(w http.ResponseWriter, r *http.Request) {w.WriteHeader(http.StatusOK)_, _ = w.Write([]byte("hello, index page"))
}func main() {http.Handle("/home", http.HandlerFunc(home))_ = http.ListenAndServe("localhost:8000", nil)
}
通常,我们还会使用另外一个函数 http.HandleFunc
,HandleFunc
的定义如下:
func HandleFunc(pattern string, handler func(ResponseWriter, *Request))
第二个参数是一个普通的函数类型,那可以直接将 home
传递给 HandleFunc
:
func main() {http.HandleFunc("/home", home)_ = http.ListenAndServe("localhost:8000", nil)
}
那如果我们看过 HandleFunc
的内部实现的话,就会知道两种写法是完全等价的,内部将第二种写法转换为了第一种写法。
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {if handler == nil {panic("http: nil handler")}mux.Handle(pattern, HandlerFunc(handler))
}
如果你仔细观察,会发现 http.ListenAndServe
的第二个参数也是接口类型 Handler
,我们使用了标准库 net/http
内置的路由,因此呢,传入的值是 nil
。那如果这个地方我们传入的是一个实现了 Handler
接口的结构体呢?就可以完全托管所有的 HTTP
请求,后续怎么路由,怎么处理,请求前后增加什么功能,都可以自定义了。慢慢地,就变成了一个功能丰富的 Web
框架了。如果你感兴趣呢,可以阅读 7天用Go从零实现Web框架Gee教程。
其他语言类似特性
如果有 Java
编程经验的同学可能比较有感触。Java 1.5
中是不支持直接传入函数的,参数要么是接口,要么是对象。举一个最简单的例子,列表自定义排序时,需要实现一个匿名的 Comparator
类,重写 compare
方法。
Collections.sort(list, new Comparator<Integer>(){@Overridepublic int compare(Integer o1, Integer o2) {return o2 - o1;}
});
Java 1.8
中引入了大量的函数式编程的特性,其中 lambda
表达式和函数式接口就是一个很好的简化 Java
写法的特性。Java 1.8
中,上述的例子可以简化为:
Collections.sort(list, (Integer o1, Integer o2) -> o2 - o1 );
即从需要构造一个匿名对象简化为只需要一个lambda
函数表达式,可以认为是面向对象与函数式编程的一种结合。同样地,这种写法只支持只定义了一个方法的接口类型,因为只定义了一个方法的接口,就会很明确传入进来的函数对应接口中的哪个方法。
正是这种结合,可以达到实现相同代码,代码量更少的目的。
相关文章:
day2加餐 Go 接口型函数的使用场景
文章目录 问题价值使用场景其他语言类似特性 问题 在 动手写分布式缓存 - GeeCache day2 单机并发缓存 这篇文章中,有一个接口型函数的实现: // A Getter loads data for a key. type Getter interface {Get(key string) ([]byte, error) }// A Getter…...

摄像头 RN6752v1 视频采集卡
摄像头 AHD倒车摄像头比较好,AHD英文全名Analog High Definition,即模拟高清,拥有比较好的分辨率与画面质感。 RN6752v1 GQW AKKY2 usb 采集卡 FHD(1080p)、HD(720p)和D1(480i&am…...

记录vivado自带IP iBert眼图近端回环
记录利用vivado自带IP核工具测试信号质量 ibert是测试眼图的工具,在使用的时候并不用改太多的内容,只需要注意参考时钟及所需要的引脚即可。由于条件的限制,并没有使用光纤和电缆进行连接进行外部回环,仅使用内部回环做测试&…...

js | Core
http://dmitrysoshnikov.com/ecmascript/javascript-the-core/ Object 是什么? 属性[[prototype]]对象。 例如,下面的,son是对象,foo不是对象。打印出来的son,能看到有一个prototype 对象。 prototype vs _proto_ v…...
Log4J reminder
Java JNDI and Log injection https://docs.oracle.com/javase/jndi/tutorial/ See also https://telegra.ph/Log4J-Vulnerability-Explained-07-21...

Unity XR Interaction Toolkit(VR、AR交互工具包)记录安装到开发的流程,以及遇到的常见问题(一)!
提示:文章有错误的地方,还望诸位大神不吝指教! 文章目录 前言一、XR Interaction Toolkit是什么?二、跨平台交互三、 AR 功能四、XR Interaction Toolkit的特点五、XR Interaction Toolkit 示例总结 前言 随着VR行业的发展&#…...

MongoDB文档整理
过往mongodb文档: https://blog.csdn.net/qq_46921028/article/details/123361633https://blog.csdn.net/qq_46921028/article/details/131136935https://blog.csdn.net/qq_46921028/article/details/139247847 1. MongoDB前瞻 1、MongoDB概述: MongoDB是…...

【AI学习】关于Scaling Law的相关学习
一、苦涩的教训 首先,学习一段重要话语: The biggest lesson that can be read from 70 years of AI research is that general methods that leverage computation are ultimately the most effective, and by a large margin. 从70年的人工智能研究中…...
学习小记-Kafka相较于其他MQ有啥优势?
Kafka 相比于 RocketMQ 有以下几个优势: 1. 高吞吐量和低延迟: Kafka 以其出色的 I/O 性能和分布式架构设计,能够实现极高的吞吐量,每秒数百万的消息处理能力,适合大规模数据流处理。同时,Kafka 设计为…...

技能 | postman接口测试工具安装及使用
哈喽小伙伴们大家好!今天来给大家分享一款轻量级,高效好用的接口测试工具-postman. Postman是一个流行的API开发工具,主要用于测试、开发和文档化API。以下是关于Postman的介绍及其主要使用场景: Postman介绍: 1. 功能丰富的API客户端&#…...

移动UI:任务中心的作用,该如何设计更合理?
任务中心是移动应用中用于展示和管理用户待办任务、提醒事项、用户福利、打卡签到等内容的功能模块。合理设计任务中心可以提升用户体验和工作效率。 以下是一些设计任务中心的合理建议: 1. 易于查看和管理: 任务中心的设计应该使用户能够快速、直观地…...

pytorch学习(十)优化函数
优化函数主要有,SGD, Adam,RMSProp这三种,并且有lr学习率,momentum动量,betas等参数需要设置。 通过这篇文章,可以学到pytorch中的优化函数的使用。 1.代码 代码参考《python深度学习-基于pytorch》&…...
Ubuntu22.04:安装Samba
1.安装Samba服务 $ sudo apt install samba samba-common 2.创建共享目录 $ mkdir /home/xxx/samba $ chmod 777 /home/xxx/samba 3.将用户加入到Samba服务中 $ sudo smbpasswd -a xxx 设置用户xxx访问Samba的密码 4.配置Samba服务 $ sudo vi /etc/samba/smb.conf 在最后加入 …...
Powershell 使用介绍
0 Preface/Foreword 0.1 参考文档 Starting Windows PowerShell - PowerShell | Microsoft Learn 1 Powershell 介绍 2 命令介绍 2.1 新建文件夹 New-Item -Path C:\GitLab-Runner -ItemType Directory 2.2 切换路径 cd C:\GitLab-Runner 2.3 下载文件 Invoke-WebRequ…...

【Langchain大语言模型开发教程】记忆
🔗 LangChain for LLM Application Development - DeepLearning.AI 学习目标 1、Langchain的历史记忆 ConversationBufferMemory 2、基于窗口限制的临时记忆 ConversationBufferWindowMemory 3、基于Token数量的临时记忆 ConversationTokenBufferMemory 4、基于历史…...

最新Qt6的下载与成功安装详细介绍
引言 Qt6 是一款强大的跨平台应用程序开发框架,支持多种编程语言,最常用的是C。Qt6带来了许多改进和新功能,包括对C17的支持、增强的QML和UI技术、新的图形架构,以及构建系统方面的革新。本文将指导你如何在Windows平台上下载和安…...

LeetCode 热题 HOT 100 (001/100)【宇宙最简单版】
【链表】 No. 0160 相交链表 【简单】👉力扣对应题目指路 希望对你有帮助呀!!💜💜 如有更好理解的思路,欢迎大家留言补充 ~ 一起加油叭 💦 欢迎关注、订阅专栏 【力扣详解】谢谢你的支持&#x…...

Ubantu 使用 docker 配置 + 远程部署 + 远程开发
大家好我是苏麟 , Ubantu 一些配置 . 视频 : 服务器很贵?搞台虚拟机玩玩!保姆级 Linux 远程开发教程_哔哩哔哩_bilibili Docker安装及配置 安装命令 : sudo apt install docker.io 查看版本号 : docker -v 查看虚拟机地址命令 : ifconfig 虚拟机地址 或…...

应用层自定义协议与序列化
个人主页:Lei宝啊 愿所有美好如期而遇 协议 简单来说,就是通信双方约定好的结构化的数据。 序列化与反序列化 我们通过一个问题引入这个概念,假如我们要实现一个网络版的计算器,那么现在有两种方案,第一种&#x…...

Python学习笔记—100页Opencv详细讲解教程
目录 1 创建和显示窗口... - 4 - 2 加载显示图片... - 6 - 3 保存图片... - 7 - 4 视频采集... - 8 - 5视频录制... - 11 - 6 控制鼠标... - 12 - 7 TrackBar 控件... - 14 - 8.RGB和BGR颜色空间... - 16 - 9.HSV和HSL和YUV.. - 17 - 10 颜色空间的转化... - 18 - …...

SpringBoot-17-MyBatis动态SQL标签之常用标签
文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...

Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动
一、前言说明 在2011版本的gb28181协议中,拉取视频流只要求udp方式,从2016开始要求新增支持tcp被动和tcp主动两种方式,udp理论上会丢包的,所以实际使用过程可能会出现画面花屏的情况,而tcp肯定不丢包,起码…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
Objective-C常用命名规范总结
【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名(Class Name)2.协议名(Protocol Name)3.方法名(Method Name)4.属性名(Property Name)5.局部变量/实例变量(Local / Instance Variables&…...
2024年赣州旅游投资集团社会招聘笔试真
2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...

JVM虚拟机:内存结构、垃圾回收、性能优化
1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...