你Go代码写的像“鸭子”吗???

概 述

Go 语言也提供了接口类型,使得我们可以面向接口编程,将实现和接口分离。在我看来,软件的抽象之美也应该以此来表达,和 Java 语言不同的是 Go 并不是那么 “强制”,它使用了一种 鸭子类型 的方式让动态类型成为可能。

Duck Typing

在 Go 中没有 implements 和 extends 这种关键字,这对我们而言反倒轻松了一些,它认为 Go 的接口就像鸭子测试里的描述:

当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。

在鸭子类型中,关注点在于对象的行为,能做什么;而不是关注对象所属的类型。例如,在不使用鸭子类型的语言中,我们可以编写一个函数,它接受一个类型为 “鸭子” 的对象,并调用它的 “走” 和 “叫” 方法。

在使用鸭子类型的语言中,这样的一个函数可以接受一个任意类型的对象,并调用它的 “走” 和 “叫” 方法。如果这些需要被调用的方法不存在,那么将引发一个运行时错误。

任何拥有这样的正确的 “走” 和 “叫” 方法的对象都可被函数接受的这种行为引出了以上表述,这种决定类型的方式因此得名。

啥是鸭子🦆???

我们用 Go 语言来实现一个鸭子类型:

type Duck interface {Swim()    // 游泳Feathers() // 羽毛
}

这里使用 Go 提供的 interface 关键字定义了一个鸭子接口类型,这个接口中提供了鸭子的两种行为:游泳和羽毛是什么样的,但是没有提供实现。

我们见过的鸭子类型可多了去了,下面是你可能见过的:

组合接口

现在我们给鸭子再添加一种嘎嘎叫的能力,一种方式是在原有的接口上添加 “嘎嘎叫” 方法,这样做的话就表示所有的鸭子都应该拥有此能力,假设我们的玩具鸭并不能开口嘎嘎叫,所以它没有这种能力。这时候我们可以将会嘎嘎叫的鸭子单独定义一种类型,在 Go 可以使用组合的方式来实现:

type QuackDuck interface {Quack()  // 嘎嘎叫Duck     // 嵌入接口
}

这样 QuackDuck 类型就拥有了之前 Duck 提供的两种抽象能力,同时还应该拥有嘎嘎叫的能力。

接口实现

前面我们只给出了鸭子的能力定义,还没有任何实现,由于 Go 中没有继承和实现的关键字,想成为上述接口的实现非常简单,只要实现它们定义的方法就可以了。

// RealDuck - 真正的鸭子
type RealDuck struct { }func (RealDuck) Swim() {fmt.Println("用鸭璞向后划水")
}func (RealDuck) Feathers() {fmt.Println("遇到水也不会湿的羽毛")
}func (RealDuck) Quack() {fmt.Println("嘎~ 嘎~ 嘎~")
}// ToyDuck - 玩具鸭
type ToyDuck struct { }func (ToyDuck) Swim() {fmt.Println("以固定的速度向前移动")
}func (ToyDuck) Feathers() {fmt.Println("白色的固定的塑料羽毛")
}

可以看到我们定义了两种鸭子类型,一种是真正的鸭子,它还多实现了一种嘎嘎叫方法,另一个玩具鸭子只有游泳和羽毛这两种行为。

这个编程方式和我们写普通的结构体方法没什么区别,只是对应的方法签名相同,其实这种方式在 Go 语言的标准库中有特别多的应用,比如:io.Reader、io.Writer 和 io.Closer

接口使用

接下来我们可以使用一下这个类型了:

var duck Duck
duck = ToyDuck{}
duck.Swim()
duck.Feathers()

输出

以固定的速度向前移动 白色的固定的塑料羽毛 由于玩具鸭没有嘎嘎叫的能力,所以如果你这么写编译无法通过

错误实现

我们也可以用一种工厂的方式来进行调用:

func Factory(name string) Duck {switch name {case "toy":return &ToyDuck{}case "real":return &RealDuck{}default:panic("No such duck")}
}func main() {duck := Factory("toy")duck.Swim()duck.Feathers()
}

小 结

其实这就是 Go 中的多态体现,仔细体会其中的味道,在阅读其他源码的时候你会更加熟练。但是也有一个问题当代码工程庞大的时候你很难知道一个接口体到底实现了哪些接口,不过有幸的是我们生在最智能的 IDE 时代,在 GoLand 中可以帮你提示。

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

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

相关文章

three.js : tweenjs创建threejs动画

效果&#xff1a; 代码 <template><div><el-container><el-main><div class"box-card-left"><div id"threejs" style"border: 1px solid red"></div> <div class"box-right"><…

超凡脱俗的 sudo

文章目录 超凡脱俗的 sudo语法 没有sudo权限的用户指定用户执行命令列出目前sudo的权限使用sudo快速统计家目录的使用情况更多信息 超凡脱俗的 sudo Linux sudo命令以系统管理者的身份执行指令&#xff0c;也就是说&#xff0c;经由 sudo 所执行的指令就好像是 root 亲自执行。…

selenium自动发数据到console并获取返回数据

# 导入selenium库 from time import sleep from selenium import webdriver from selenium.webdriver.common.by import By# 创建一个Chrome浏览器对象 options webdriver.ChromeOptions() #最大化窗口 options.add_argument("start-maximized") #自动打开开发者工具…

认识SpringBoot中的条件注解

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; 循序渐进学SpringBoot ✨特色专栏&…

Hive之set参数大全-4

F 指定在使用 FETCH 命令提取查询结果时的序列化/反序列化器 hive.fetch.output.serde 是 Hive 的一个配置参数&#xff0c;用于指定在使用 FETCH 命令提取查询结果时的序列化/反序列化器。 以下是一个示例&#xff1a; -- 设置 hive.fetch.output.serde 为 org.apache.had…

虚幻引擎:开创视觉与创意的新纪元

先看看据说虚幻5做出来的东西吧&#xff1a; 虚幻引擎5&#xff01;&#xff01;&#xff01;4K画质PS5实机演示&#xff01; 好了&#xff0c;用文字认识一下吧&#xff1a; 虚幻引擎5.3对UE5的核心工具集作了进一步优化&#xff0c;涉及渲染、世界构建、程序化内容生成&…

Linux kernel 学习笔记

几个推荐的网站或邮件列表&#xff1a; https://elixir.bootlin.com/linux/latest/source&#xff0c; 在线查看Linux源码https://kernelnewbies.org/LinuxVersions&#xff0c;查看Linux kernel每一个历史版本的主要变化https://kernelnewbies.org/&#xff0c;是一方适合内核…

【解刊】Elsevier旗下,1区CCF-B,超快审稿:2个月22天录用!

计算机类 • 升区期刊 本次带来Elsevier旗下高分快刊&#xff0c;入选CCF-B类推荐&#xff0c;如有相关领域作者意向投稿&#xff0c;可重点关注&#xff01;更多领域期刊&#xff0c;可移步公众号【Unionpub学术】了解详情~ 01 期刊简介 Computer Networks ✅出版社&#x…

14:00面试,14:07就出来了,问的问题有点变态。。。

前言 刚从小厂出来&#xff0c;没想到在另一家公司我又寄了。 在这家公司上班&#xff0c;每天都要加班&#xff0c;但看在钱给的比较多的份上&#xff0c;也就不太计较了。但万万没想到一纸通知&#xff0c;所有人不准加班了&#xff0c;不仅加班费没有了&#xff0c;薪资还…

GIS入门,JavaScript如何将度分秒(°′″)格式的经纬度数据转换为十进制小数格式

前言 本章讲解JavaScript如何将度分秒格式(′″)的经纬度数据转换为十进制小数格式。 比如将 "4030′30″(纬度:40度30分30秒)转换为,12020′15″(经度: 120度20分15秒)转换为 40.508333,120.337500 实现功能 将度分秒格式(′″)的经纬度转换为十进制小数格…

回顾基础--HTML篇

HTML语法规范 <html></html> 开始标签与结束标签 <br /> 单标签 包含关系 <head><title></title> </head>并列关系 <head></head> <body></body> 1、 标题标签 标题标签 【双标签】【不同标题字体大小…

GBASE南大通用Parameter 属性

SQL 语句或者存储过程使用的参数集合 GBASE南大通用ParameterCollection&#xff0c;默认是空集合。  语法 [Visual Basic] Public ReadOnly Property Parameters As GBaseParameterCollection Get [C#] public GBaseParameterCollection Parameters { get; }  注释…

计算机网络-各层协议

大家在搞嵌入式开发的时候基本都了解过七层网络协议、五层网络协议、四层网络协议&#xff0c;那么今天让我们更加的深入了解一下&#xff1a; 历史发展介绍 OSI七层模型由ISO国际标准化组织提出的通信标准。TCP/IP四层模型是OSI七层模型的简化版&#xff0c;OSI在它被官方完…

论文阅读1---OpenCalib论文阅读之factory calibration模块

前言 该论文的标定间比较高端&#xff0c;一旦四轮定位后&#xff0c;可确定标定板与车辆姿态。以下为本人理解&#xff0c;仅供参考。 工厂标定&#xff0c;可理解为车辆相关的标定&#xff0c;不涉及传感器间标定 该标定工具不依赖opencv&#xff1b;产线长度一般2.5米 Fa…

浅谈WAF——守护网络安全的无形之盾

随着信息化时代的到来&#xff0c;网络已逐渐融入我们日常生活的方方面面。然而&#xff0c;与此同时&#xff0c;网络安全问题却也如影随形。为此&#xff0c;一种名为“Web应用防火墙”的工具应运而生&#xff0c;简称”WAF”。 WAF是什么&#xff1f; WAF&#xff08;Web …

用js将geojson转换成WKT格式并插入到数据库

用js将geojson转换成WKT格式并插入到数据库 var fs require("fs"); var mysql require("mysql"); var Geojson2wkt require("Geojson2Wkt");var connection mysql.createConnection({host: "172.16.2.252",port: 3316,user: &quo…

Python string模块中Template的substitute()使用

一、模板字符串 模板字符串提供了由 PEP 292 所描述的更简便的字符串替换方式。 模板字符串的一个主要用例是文本国际化 (i18n)&#xff0c;因为在此场景下&#xff0c;更简单的语法和功能使得文本翻译过程比使用 Python 的其他内置字符串格式化工具更为方便。 作为基于模板字符…

实现LCM在docker之间的通信

目录 1.docker容器互联 新建网络 连接容器 2.设置环境变量 3.在两个docker之间实现通信 1.docker容器互联 新建网络 $ docker network create -d bridge test-net 连接容器 运行一个容器并连接到新建的 test-net 网络: $ docker run -itd --name lcm_1 --network tes…

通过iFrame嵌入Grafana页面或pannel

前言 在当前数据驱动的时代&#xff0c;有效地可视化和监控关键性能指标变得至关重要。Grafana&#xff0c;作为一个开源的监控解决方案&#xff0c;提供了强大的功能来呈现和分析数据&#xff0c;从而帮助用户及时洞察和响应各种情况。随着技术的不断发展&#xff0c;将这些信…

docker 容器添加指定网络地址

docker 容器添加指定网络地址 在搭建halo博客时&#xff0c;准备让 halo、mysql8.1、nginx 三个容器在同一个网段中&#xff0c;并指定IP。 实现docker内部容器之间网络互通。 查看容器网络信息命令 docker inspect 容器名各容器部署成功后网络效果如下&#xff1a; nginx …