【SpinalHDL】Scala编程之伴生对象

Scala中的伴生对象是指和在同一个文件中声明的,并且和类同名的对象。例如,下面的代码保存在名为Pizza的文件中。在Scala中,这个object Pizza 对象被认为是class Pizza 类的伴生对象:

class Pizza {
}
object Pizza {
}

这样设计的优势是伴生对象及其类可以访问彼此的私有成员(字段方法),这意味着这个类中的printFilename 方法可以工作,因为它可以访问它的伴生对象中的HiddenFilename字段:

class SomeClass {def printFilename() = {println(SomeClass.HiddenFilename)}
}
object SomeClass {private val HiddenFilename = "/tmp/foo.bar"
}

伴生对象提供的功能远不止这些,我们将在本课剩下的内容中演示它的几个最重要的功能。

不使用关键字new创建新实例

在一些Spinalhdl示例中创建某些类的新实例时不必在类名之前使用关键字new,如下面的例子所示:

val zenMasters = List(Person("Nansen"),Person("Joshu")
)

这个功能来自于伴生对象的使用。当伴生对象中定义一个方法时,它对Scala编译器有特殊的意义。Scala内置了一些语法糖,可以让你输入这样的代码: apply

val p = Person("Fred Flinstone")

在编译过程中,编译器将该代码转换为以下代码:

val p = Person.apply("Fred Flinstone")

伴生对象中的apply 方法就像一个工厂方法,Scala的语法糖允许你使用上面的语法,不用关键字就能创建新new的类实例:

启用功

为了演示这个功能是如何工作的,下面是一个Person类名和它的伴生对象中的apply方法:

class Person {var name = ""
}
object Person {def apply(name: String): Person = {var p = new Personp.name = namep}
}

为了测试这段代码,可以使用下面的技巧将类和对象同时粘贴到Scala REPL中:

  • 从命令行启动Scala REPL(使用如下命令)
  • scala 输入paste 并按[Enter]键 :
  • REPL的响应应该是这样的:
// Entering paste mode (ctrl-D to finish)
  • 现在将类和对象同时粘贴到REPL中
  • 按Ctrl-D完成“paste”过程
    当这个过程正常运行时,你应该在REPL中看到如下输出:
defined class Person
defined object Person

REPL要求使用这种技术同时输入一个类和它的伴生对象。

现在可以像这样创建一个类的新实例: Person

val p = Person.apply("Fred Flinstone")

该代码直接调用伴生对象。更重要的是还可以像这样创建一个新实例: apply

val p = Person("Fred Flinstone")

更加便利使用此功能如下

val zenMasters = List(Person("Nansen"),Person("Joshu")
)

需要说明的是,在这个过程中发生的是:

  • 输入 val p = Person(“Fred”)
  • Scala编译器会发现 new Person之前没有关键字
  • 编译器会在类的伴生对象中查找与输入的类型签名匹配的方法 apply Person
  • 如果找到方法就使用它 apply,如果没有会得到一个编译错误

创建多个构造函数

可以在一个伴生对象中创建多个方法来提供多个构造函数。下面的代码展示了如何创建一个和两个参数的构造函数。

class Person {var name: Option[String] = Nonevar age: Option[Int] = Noneoverride def toString = s"$name, $age"
}
object Person {// a one-arg constructordef apply(name: Option[String]): Person = {var p = new Personp.name = namep}// a two-arg constructordef apply(name: Option[String], age: Option[Int]): Person = {var p = new Personp.name = namep.age = agep}
}

如果像之前那样将代码粘贴到REPL中,你会看到可以像下面这样创建新实例: Person

val p1 = Person(Some("Fred"))
val p2 = Person(None)
val p3 = Person(Some("Wilma"), Some(33))
val p4 = Person(Some("Wilma"), None)

打印这些值,会得到如下结果:

val p1: Person = Some(Fred), None
val p2: Person = None, None
val p3: Person = Some(Wilma), Some(33)
val p4: Person = Some(Wilma), None

运行这样的测试时最好清除REPL的内存 :reset:paste

添加unapply方法

就像在伴生对象中添加apply方法可以构造新的对象实例一样,添加unapply方法可以反构造对象实例。我们将用一个例子来演示:
下面是一个Person类及其伴生对象的不同版本:

class Person(var name: String, var age: Int)
object Person {def unapply(p: Person): String = s"${p.name}, ${p.age}"
}

注意伴生对象定义了一个unapply方法。这个方法接受Person类型为的输入参数,并返回String。要手动测试该unapply方法首先创建一个新Person实例:

val p = new Person("Lori", 29)

然后像这样unapply测试:

val result = Person.unapply(p)

这是REPL中的unapply结果:

scala> val result = Person.unapply(p)
result: String = Lori, 29

如上所示对给定的实例进行解构。
在Scala中把一个unapply方法放在伴生对象中时,我们就说你创建了一个提取器方法,因为你已经创建了一种从Person对象中提取字段的unapply方法:

unapply 返回不同类型

在上面例子中unapply返回String a,但也可以让它返回任何东西。下面的示例返回元组中的两个字段:

class Person(var name: String, var age: Int)
object Person {def unapply(p: Person): Tuple2[String, Int] = (p.name, p.age)
}

这个方法在REPL中如下所示:

scala> val result = Person.unapply(p)
result: (String, Int) = (Lori,29)

因为这个unapply方法以元组的形式返回类字段,所以你也可以这样做:

scala> val (name, age) = Person.unapply(p)
name: String = Lori
age: Int = 29

unapply 提取器

创建提取器的一个好处是,如果你遵循正确的Scala约定,它们会在匹配表达式中启用一种方便的模式匹配形式

要点

  • 伴生对象是与A在同一个文件中声明的,并且与类 objectclass同名
  • 伴生对象及其类可以访问彼此的私有成员
  • 伴生对象的apply方法让你无需使用关键字 new就能创建类的新实例
  • 伴生对象的unapply方法允许你将一个类的实例解构为它的各个组件

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

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

相关文章

【Spring】IocDI详解(6)

本系列共涉及4个框架:Sping,SpringBoot,Spring MVC,Mybatis。 博客涉及框架的重要知识点,根据序号学习即可。 有什么不懂的都可以问我,看到消息会回复的,可能会不及时,请见谅!! 目录 本系列共…

Excel 国产化替换新方案

前言 在当前数字化转型和信创(信息技术应用创新)战略背景下,企业对于安全性、自主可控性和高效办公工具的需求日益增加。作为一款国产自主研发的高性能表格控件,SpreadJS 正成为替换 Excel 的最佳选择。它不仅全面支持国产化认证…

头部姿态估计代码+教程

前言 头部姿态估计是计算机视觉中的一个具有挑战性的问题,因为它需要完成多个步骤。首先,我们需要在画面中定位人脸,然后识别出各种面部特征点。如今,当人脸正对摄像头时,识别人脸似乎是一个简单的任务。但问题在于&am…

PCIe进阶之TL:First/Last DW Byte Enables Rules Traffic Class Field

1 First/Last DW Byte Enables Rules & Attributes Field 1.1 First/Last DW Byte Enables Rules Byte Enable 包含在 Memory、I/O 和 Configuration Request 中。本文定义了相应的规则。Byte Enable 位于 header 的 byte 7 。对于 TH 字段值为 1 的 Memory Read Request…

计算机网络27、28——Linux命令1、2

1、虚拟机网络前方路径内容 用户名机器名:/$ $表示普通用户,#表示root用户 2、Linux不分盘,都是绝对路径 /表示根目录,表示计算机文件夹下 ~是当前用户的家,表示home文件夹下自己的文件夹 3、bin文件夹下的是可执…

信息收集常用指令

目的 本文主要是记录一些在信息搜集时,常用的提高搜索效率的命令。 后续会继续记录一些用到的更多指令和方法,慢慢更新。 1、inurl “inurl:xxx”是指查找url中包含xxx的网页。 URL:统一资源定位符。统一资源定位系统。可以说包含域名&am…

【数据结构-差分】力扣1589. 所有排列中的最大和

有一个整数数组 nums ,和一个查询数组 requests ,其中 requests[i] [starti, endi] 。第 i 个查询求 nums[starti] nums[starti 1] … nums[endi - 1] nums[endi] 的结果 ,starti 和 endi 数组索引都是 从 0 开始 的。 你可以任意排列…

查看TCP/UDP网络连接通信情况

绪论​ “宿命论是那些缺乏意志力的弱者的借口。 ——罗曼.罗兰” 话不多说安全带系好,发车啦(建议电脑观看)。 主要使用: nestat -nltp n 拒绝显示别名,能显示数字的全部转化成数字l 仅列出有在 Listen (…

动态SQL中的foreach标签【后端 21】

动态SQL中的foreach标签 在Java开发中&#xff0c;特别是在使用MyBatis进行数据库操作时&#xff0c;动态SQL是一项非常强大的功能。MyBatis的<foreach>标签就是动态SQL中最为常用的一个&#xff0c;主要用于处理包含IN子句的查询或者批量插入等操作。本文将详细介绍<…

《程序猿之设计模式实战 · 策略模式》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; CSDN入驻不久&#xff0c;希望大家多多支持&#xff0c;后续会继续提升文章质量&#xff0c;绝不滥竽充数…

论文内容分类与检测系统源码分享

论文内容分类与检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Comput…

掌握顶会流量密码!“Mamba+CNN”双热点组合!轻松找到创新点!

传统视觉模型在处理大规模或高分辨率图像时存在一定限制。然而Mamba与CNN相结合&#xff0c;在处理序列数据和图像数据时有着显著的优势&#xff0c;并且能够有效提升模型计算效率和准确率。 这种结合可以让Mamba在处理长序列数据时既能够捕捉到序列中的时间依赖关系&#xff…

Vue使用qrcodejs2-fix生成网页二维码

安装qrcodejs2-fix npm install qrcodejs2-fix核心代码 在指定父view中生成一个二维码通过id找到父布局 //通过id找到父布局let codeView document.getElementById("qrcode")new QRCode(codeView, {text: "测试",width: 128,height: 128,colorDark: #00…

three.js 热力图

使用three.js 和 heatMap.js 实现在 三维场景中展示热力图的效果&#xff0c;以下代码复制粘贴即可在你的本机运行。 在线编辑运行预览可方位 https://threehub.cn/#/codeMirror?navigationThreeJS&classifyexpand&idheatmap3D 在 https://threehub.cn 中还有很多案例…

力扣 中等 2300.咒语和药水的成功对数

文章目录 题目介绍解法 题目介绍 解法 class Solution {public int[] successfulPairs(int[] spells, int[] potions, long success){Arrays.sort(potions);int n spells.length, m potions.length;int[] pairs new int[n];for (int i 0; i < n; i) {int left 0, righ…

【leetcode】树形结构习题

二叉树的前序遍历 返回结果&#xff1a;[‘1’, ‘2’, ‘4’, ‘5’, ‘3’, ‘6’, ‘7’] 144.二叉树的前序遍历 - 迭代算法 给你二叉树的根节点 root &#xff0c;返回它节点值的 前序 遍历。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,…

汉王手写签批控件如何在谷歌、火狐、Edge等浏览器使用

背景 近日&#xff0c;有网友咨询汉王手写签批控件是否可以通过allWebPlugin中间件技术加载到谷歌、火狐、Edge等浏览器&#xff1f;为此&#xff0c;笔者详细了解了一下汉王手写签批控件&#xff0c;它是一个标准的ActiveX控件&#xff0c;曾经主要在IE浏览器使用&#xff0c;…

C语言 | Leetcode C语言题解之第401题二进制手表

题目&#xff1a; 题解&#xff1a; char** readBinaryWatch(int turnedOn, int* returnSize) {char** ans malloc(sizeof(char*) * 12 * 60);*returnSize 0;for (int i 0; i < 1024; i) {int h i >> 6, m i & 63; // 用位运算取出高 4 位和低 6 位if (h &…

Laravel邮件发送:从配置到发邮件的指南!

Laravel邮件发送功能如何实现&#xff1f;怎么使用Laravel发信&#xff1f; Laravel作为一款流行的PHP框架&#xff0c;提供了强大且易用的邮件发送功能。AokSend将详细介绍如何从配置到实际发送邮件的全过程&#xff0c;帮助你快速掌握Laravel邮件发送的技巧。 Laravel邮件发…

对 JavaScript 原型的理解

笔者看了一些有关 JavaScript 原型的文章有感而发&#xff0c;就将所感所悟画了下来如果有理解错误和不足的地方&#xff0c;欢迎各位大佬指出&#xff0c;笔者感激不尽