[读书日志]从零开始学习Chisel 第十二篇:Scala的抽象成员(敏捷硬件开发语言Chisel与数字系统设计)

embedded/2025/1/25 14:47:51/

9. Scala的抽象成员

9.1 抽象成员

Scala有4种抽象成员,分别是抽象val字段,抽象var字段,抽象方法和抽象类型。声明如下:

scala">scala> trait Abstract {| type T					    //抽象类型| def transform(x: T): T		 //抽象方法| val initial: T				//抽象val字段| var current: T				//抽象var字段| }
// defined trait Abstract

抽象类和特质不能直接使用new构造实例,只能由子类继承后实现它们。抽象类型指的是用关键字type声明的一种类型,它是某个类或特质的成员但未给出定义。

在不知道某个字段正确的值,但是明确知道在当前类的每个实例中,该字段都会有一个不可变更的值,可以使用抽象val字段。抽象val字段与无参方法类似,抽象字段保证每次使用都返回一个相同的值,抽象方法每次可能返回不一样的值。

抽象var字段和抽象val字段类似,但可以被重新赋值。

9.2 初始化抽象val字段

抽象val字段有时会承担超类参数的作用,它们允许程序员在子类中提供在超类中缺失的细节。

例如有如下特质:

scala">trait RationalTrait {val numerArg: Intval denomArg: Int
}

要在具体的类中混入这个特质,必须实现它的两个抽象val字段:

scala">new RationalTrait {val numerArg = 1val denomArg = 1
}

前面讲过,这不是直接实例化特质,而是隐式用一个匿名类混入了该特质。花括号中的内容属于隐式的匿名类。

在构造子类的实例对象时,首先构造超类/超特质的组件,然后才轮到子类的剩余组件。由于花括号中的内容不属于超类/超特质,所以在构造超类/超特质的组件时,花括号内的内容其实是无用的。在这个过程中,如果需要访问超类/超特制的抽象val字段,会交出相应类型的默认值,而不是花括号中的定义。只有轮到构造子类的剩余组件时,花括号的子类定义才能派上用场。例如下面这段代码:

scala">scala> trait RationalTrait {| val numerArg: Int| val denomArg: Int| require(denomArg != 0)| }
// defined trait RationalTraitscala> new RationalTrait {| val numerArg = 1| val denomArg = 1| }
java.lang.IllegalArgumentException: requirement failedat scala.Predef$.require(Predef.scala:324)at rs$line$82$RationalTrait.$init$(rs$line$82:4)... 31 elided

针对这样的情况有以下两种解决方法:

9.2.1 预初始化字段

书上预初始化字段的形式是:

new { 定义 } with 超类/超特质

书上有如下示例:

scala">scala> new {| val numerArg = 1| val denomArg = 2| } with RationalTrait
-- [E009] Syntax Error: ------------------------------------------------------------------------
4 |} with RationalTrait|  ^^^^|  Early definitions are not supported; use trait parameters instead|| longer explanation available when compiling with `-explain`
-- [E018] Syntax Error: ------------------------------------------------------------------------
4 |} with RationalTrait|                    ^|                    expression expected but eof found|| longer explanation available when compiling with `-explain`

实际上这个语法在Scala3中已经不再支持。这个方案不被支持,只能使用下一种方法:

9.2.2 惰性的val字段

val字段定义成惰性的,可以让程序自己确定初始化顺序,如果在val字段前加上关键字lazy,那么该字段只有在首次被使用才会进行初始化。如果是用表达式初始化,那就对表达式求值并保存,后续使用字段时都复用保存的结果而不是每次都求值表达式。

scala">scala> trait LazyRationalTrait {| val numerArg: Int| val denomArg: Int| lazy val numer = numerArg / g| lazy val denom = denomArg / g| override def toString = numer + "/" + denom| private lazy val g = {| require(denomArg != 0)| gcd(numerArg, denomArg)| }| private def gcd(a: Int, b: Int): Int =| if (b == 0) a else gcd(b, a % b)| }
there was 1 deprecation warning; re-run with -deprecation for details
1 warning found
// defined trait LazyRationalTraitscala> val x = 2
val x: Int = 2scala> new LazyRationalTrait {| val numerArg = 1 * x| val denomArg = 2 * x| }
val res37: LazyRationalTrait = 1/2
9.3 Sacla的枚举

Scala在标准库中提供一个枚举类,scala.Enumeration,通过创建一个继承自这个类的子对象可以创建枚举。

scala">scala> object Color extends Enumeration {| val Red, Green, Blue = Value| }
// defined object Color

Enumeration类定义了一个名为Value的内部类,以及同名的无参方法。该方法每次都返回内部类Value的全新实例,枚举对象Color的三个枚举值都分别引用了一个Value类型的实例对象。Value是内部类,所以它的对象的具体类型与外部类的实例对象有关。在这里外部类的对象就是自定义的Color,三个枚举值引用的对象的真正类型是Color.Value

方法Value有一个重载的版本,它接收一个字符串参数来给枚举值关联特定的名称。

scala">scala> object Color extends Enumeration {| val Red, Green, Blue = Value| }
// defined object Colorscala> object Direction extends Enumeration {| val North = Value("N")| val East = Value("E")| val South = Value("S")| val West = Value("W")| }
// defined object Directionscala> Color.values
val res38: Color.ValueSet = Color.ValueSet(Red, Green, Blue)scala> Direction.values
val res39: Direction.ValueSet = Direction.ValueSet(N, E, S, W)

枚举值从0开始编号,可以通过对象名(编号)来返回对应枚举值的名称。

scala">scala> Color(2)
val res40: Color.Value = Bluescala> Direction(0)
val res41: Direction.Value = N

http://www.ppmy.cn/embedded/154283.html

相关文章

vscode使用Marscode编程助手

下载 vscode 在插件里下载Marscode编程助手 插件完成 在这里点击安装,点击后这里出现AI编程插件。

力扣经典题目之120.三角形最小路径和

今天继续给大家分享一道力扣的做题心得今天这道题目是 120.三角形最小路径和 题目如下: 题目链接:三角形最小路径和 1,题目分析 这个问题要求我们在一个数字三角形中找到从顶部到底部的路径,使得路径上的数字总和最小。三角形的每…

Linux离线部署ELK

文章目录 前期准备开始安装安装elastic search安装logstash安装kibana 配置ELK配置ElasticSearch配置logstash配置kibana 启动ELK启动命令启动测试 设置ELK策略创建ILM策略将ILM策略与日志index关联查看索引是否被ILM策略管理 前期准备 ELK包含三部分软件 ElasticSearch用作搜…

模板方法模式详解

模板方法模式(Template Method Pattern)是一种行为型设计模式,它在方法中定义算法的框架,延迟到子类中实现。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。下面对模板方法模式进行详细讲解…

Git | git reset命令详解

关注:CodingTechWork 引言 Git 是一款非常流行的分布式版本控制工具,它帮助开发者有效地管理代码历史,支持多种功能来帮助团队协作、追踪修改和维护代码质量。git reset是 Git 中最强大、最复杂的命令之一,它的主要作用是重置当前…

【01】AE特效开发制作特技-Adobe After Effects-AE特效制作快速入门-制作飞机,子弹,爆炸特效以及导出png序列图-优雅草央千澈

【01】AE特效开发制作特技-Adobe After Effects-AE特效制作快速入门-制作飞机,子弹,爆炸特效以及导出png序列图-优雅草央千澈 开发背景 优雅草央千澈所有的合集,系列文章可能是不太适合完全初学者的,因为课程不会非常细致的系统…

flutter VoidCallBack ValueChange<T> 的函数定义

在 Flutter 中&#xff0c;VoidCallback 和 ValueChanged<T> 是两种常用的回调函数类型&#xff0c;它们通常用于处理事件或传递数据。下面是它们的详细定义及使用方式。 1. VoidCallback 函数类型 VoidCallback 是一个没有参数也没有返回值的回调函数类型。它通常用于…

windows wsl ubuntu22 远程桌面连接

转载链接&#xff1a;https://canwdev.github.io/VM%E8%99%9A%E6%8B%9F%E6%9C%BA/WSL/wsl2%20wslg%20%E9%85%8D%E7%BD%AE%E5%B9%B6%E5%BC%80%E5%90%AF%E8%BF%9C%E7%A8%8B%E6%A1%8C%E9%9D%A2%28xrdp%29/ Wsl2 wslg 配置并开启远程桌面(xrdp) 准备工作 推荐到微软应用商店下载最…