你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 中可以帮你提示。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

75应急响应-数据库漏洞口令检索应急取证箱

必要知识点 第三方应用是选择性的安装的,比如mysql,如何做好信息收集,有没有爆过它的漏洞,和漏洞探针也是获取攻击者思路的重要操作,除去本身漏洞外,提前预知或口令相关攻击也要进行筛选。 排除三方应用…

古典吉他教师阿木:来自新疆的音乐才子

阿木,全名木合汤夏甫依克,于 1990 年 10 月 8 日出生在新疆这片美丽的土地上,是一位哈萨克族人。他是英皇认证古典吉他教师、中国社会艺术吉他考级考官、中国智慧工程研究会艺术教育委员会执行委员、新疆吉他艺术节发起人之一兼评审组组长。 阿木自幼受到哥哥的影响,对吉他产生…

85.乐理基础-记号篇-力度记号

内容来源于:三分钟音乐社 上一个内容:78.乐理基础-非常见拍号如何打拍子-CSDN博客 85-78之间的内容观看索引: 腾讯课堂-三分钟音乐社-打拍子(20)-总结、重点、练习与检验方法开始看 力度记号:p、f、mp、…

linux和windows机器下创建共享文件夹

1、安装samba sudo apt-get install samba 2、创建共享文件夹 sudo mkdir /smb sudo chmod 777 /smb/ 3、备份配置 sudo cp /etc/samba/smb.conf /etc/samba/smb.conf.bak 4、修改配置 sudo vim /etc/samba/smb.conf 添加以下信息到文件结尾 [SMB share] #描述信息…

Element+vue3.0 tabel合并单元格span-method

Elementvue3.0 tabel合并单元格 span-method :span-method"objectSpanMethod"详解: 在 objectSpanMethod 方法中,rowspan 和 colspan 的值通常用来定义单元格的行跨度和列跨度。 一般来说,rowspan 和 colspan 的值应该是大于等于…

锻炼身体固然好,爱护听力也重要

新年新气象!你制定了那些新年计划和目标呢?相信健身一定在不少人的清单里。 根据美国调查网站 FiveThirtyEight 的报告的结果,新年目标的榜单前三是:减肥、健身、成为更好的人。 进入健身房,随着动感的音乐节奏朝着更强…

Map与JSONObject区别

相同点: 都可以存key-value;key是唯一的,如果key重复了会覆盖前面的 不同点: (1)JSONObject 不可以存空,Map可以存空。 (2)Map由jdk提供,JsonObject需要第三方jar包提供。…

pc下载apk文件到andriod开发板,并实现可视化

PC端安装APK下载器 点击下载 刷机精灵APK安装器 界面如下,可将下载好的apk文件,直接拖拽到该界面,然后点击安装全部按钮进行安装,安装过程中的具体状态会显示在具体的apk后面。 如下图,安装错误、安装完成等皆为apk安…

如何在IEC61850的ICD文件中添加新的DO节点

写在前面 恭喜“梅山剑客”粉丝突破1K,为了纪念这一伟大的时刻,今日发表此文, 纪念这神圣的时间节点,愿各位 青春永驻,笔耕不息。 本文参考链接: 1、61850开发知识总结与分享 2、IEC61850建模说明 1 简介…

针对大规模服务日志敏感信息的长效治理实践

文章目录 1 背景2 目标与措施3 实施3.1 脱敏工具类3.2 JSON脱敏3.3 APT自动脱敏3.3.1 本地缓存问题3.3.2 JDK序列化问题 3.4 弃用方案 4 规划5 总结 1 背景 近年来,国家采取了多项重要举措来加强个人数据保护,包括实施《中华人民共和国网络安全法》和《…

计算机网络 第1章(概述)

系列文章目录 计算机网络 第1章(概述) 文章目录 系列文章目录1. 计算机网络在信息时代的作用2. 因特网概述2.1 网络、互连网(互联网)和因特网2.2 因特网发展的三个阶段2.3 因特网的标准化工作2.4 因特网的组成 3. 三种交换方式3.…

java基本类型与包装类型之间的关系

JAVA基本类型和包装类型 前言 Java语言中的数据类型分为基本数据类型和引用类型,而我们进行Java开发的时候都听说过基本数据类型和包装类型,今天我们就来详细聊一聊Java中的基本数据类型和包装类型之间的区别。 基本数据类型 Java中的基本数据类型一共有…

Java版直播商城:电商源码、小程序、三级分销及 免 费 搭 建 方案

一、技术选型 java开发语言:java是一种跨平台的编程语言,适用于大型企业级应用开发。使用java开发直播商城可以保证系统的稳定性和可扩展性。 spring boot框架:spring boot是一个快速构建spring应用的框架,简化了开发过程&#xf…

GNN如何处理表格?

链接: https://ieeexplore.ieee.org/document/10184514 在这篇综述中,我们深入探讨了使用图神经网络(GNNs)进行表格数据学习(TDL)的领域,这是一个深度学习方法在分类和回归任务中相比传统方法表现出越来越…

Java虚拟机类加载机制探究:生命周期、初始化、使用与验证

一、java虚拟机与程序的生命周期 在如下几种情况之下,java虚拟机将结束生命周期: 执行了System.exit()方法程序正常执行结束程序在执行过程中遇到了异常或者错误而异常终止由于操作系统用出现错误而导致java虚拟机进程终止 二、类的加载,链…

2023年度总结:但行前路,不负韶华

​ 🦁作者简介:一名喜欢分享和记录学习的在校大学生 🐯个人主页:妄北y 🐧个人QQ:2061314755 🐻个人邮箱:2061314755qq.com 🦉个人WeChat:Vir2021GKBS &#x…

Pure Mathematics 3-(磨课课件)-反三角函数求导(更新中)

6.6 Differentiating trigonometric functions(反三角函数求导) Edexcel Pure Mathematics 3(2018版本教材) /-------------------------------------------------------------------------------------------------------------------- Prior Knowledge…

第三十八周周报:文献阅读 +BILSTM+GRU+Seq2seq

目录 摘要 Abstract 文献阅读:耦合时间和非时间序列模型模拟城市洪涝区洪水深度 现有问题 提出方法 创新点 XGBoost和LSTM耦合模型 XGBoost算法 ​编辑 LSTM(长短期记忆网络) 耦合模型 研究实验 数据集 评估指标 研究目的 洪…

双向冒泡排序的数据结构实验报告

目录 实验目的: 实验内容(实验题目与说明) 算法设计(核心代码或全部代码) 运行与测试(测试数据和实验结果分析) 总结与心得: 实验目的: 理解双向冒泡排序算法的原…

2024年AI红利:抓住AI内容写作、绘画、数字人、等四大变现机遇

2023年见证了人工智能大模型的爆发,其影响力超出了科技界范畴,成为推动社会进步的重要力量。大模型的突破性进展引起了全球关注,被视为科技发展4.0时代的革命性创新。而每一次革命性创新都是一把双刃剑,随之而来的互联网大裁员事件…