[读书日志]从零开始学习Chisel 第六篇:Scala面向对象编程——特质(敏捷硬件开发语言Chisel与数字系统设计)

3.4特质
3.4.1什么是特质

特质使用trait开头,它与单例对象很像,两者都不能有输入参数,但单例对象是具体的,特质是抽象的。两者都不能用new实例化,类,单例对象,特质三者内部都可以包含字段和方法,以及其他类,单例对象,特质的定义。

特质可以被其他类,单例对象和特质“混入”。混入在超类调用上采用线性化机制,在其他方面其实和继承是一样的。某个类混入一个特质后,会包含特质的所有公有成员,可以通过override来重写特质的成员。Scala只允许继承自一个类,但是对特质的混入数量没有限制,因此用来替代多重继承的语法。要混入一个特质,可以使用关键字extend,已被占用后可以使用with混入其他特质。

scala> class A {
     | val a = "Class A"
     | }
// defined class A

scala> trait B {
     | val b = "Trait B"
     | }
// defined trait B

scala> trait C {
     | val c = "Trait C"
     | }
// defined trait C

scala> object D extends A with B with C
// defined object D

scala> D.a
val res7: String = Class A

scala> D.b
val res8: String = Trait B

scala> D.c
val res9: String = Trait C

特质也定义了一个类型,可以指向混入该特质的对象。

scala> trait A
// defined trait A

scala> class B extends A
// defined class B

scala> val x: A = new B
val x: A = B@39159b14
3.4.2特质的层次

特质也可以继承自其他类,或混入任意多个特质,对混入有一个限制条件,即要混入该特质的类/单例对象/特质,它的超类必须是待混入特质的超类,或是待混入特质的超类的子类。换句话说,一个特质如果想要“继承”(注意,这里的“继承”实际上是“混入”,只是为了理解特质用来替代多重继承的特质。)另一个特质,那么它只能继承比它层级更低的特质。

scala> class A
// defined class A

scala> class B extends A
// defined class B

scala> class C
// defined class C

scala> trait D extends A
// defined trait D

scala> trait E extends B
// defined trait E

scala> class Test1 extends D
// defined class Test1

scala> class Test2 extends A with D
// defined class Test2

scala> class Test3 extends B with D
// defined class Test3

scala> class Test4 extends C with D
-- Error: --------------------------------------------------------------------------------------------------------------
1 |class Test4 extends C with D
  |                           ^
  |                           illegal trait inheritance: superclass C does not derive from trait
 D's superclass A
1 error found

scala> class Test5 extends A with E
-- Error: --------------------------------------------------------------------------------------------------------------
1 |class Test5 extends A with E
  |                           ^
  |                           illegal trait inheritance: superclass A does not derive from trait
 E's superclass B
1 error found

画图表示如下:

在这里插入图片描述

Test4继承自classC,它混入的特质是traitD,该特质的超类是classA,它不是classC的超类或超类的子类,因此无法混入;Test5继承自classA,它混入的traitE继承自classB,但classBclassA的子类,因此不能混入。如果把它们换一下顺序,使Test6继承classB而混入一个超类是classA的特质traitD,那么则可以运行。这个例子说明,一个类或特质的超类是哪个,是由extends关键字决定的。

scala> class Test6 extends B with D
// defined class Test6
3.4.3混入特质的简便方法

如果要快速构建一个混入某些特质的实例,可以使用这个语法:

new Trait1 with Trait2 ... {definition}

这句话定义了一个匿名类,匿名类混入了这些特质。还可以在最前面加上一个想要继承的超类:

new SuperClass with Trait1 with Trait2 ... {definition}

3.4.4特质的线性化叠加计算

多重继承中一个很明显的问题是当子类调用超类的方法时,若多个超类都有该方法的不同实现,那么需要额外的语法确定具体调用哪个版本。Scala的特质采取一种线性化的规则来调用特质中的方法,在特质中,super调用是动态绑定的,按特质本身的定义,无法确定super调用的具体行为,直到特质混入某个类或别的特质,有了具体的超类方法,才能确定super的行为,这是实现线性化的基础。

若要通过混入特质来实现某个方法的线性叠加,有以下几个要求:

  1. 需要在特质中定义同名同参的方法,并加关键字组合abstract override,这个关键词不是重写,只能用于特质中;
  2. 该特质必须混入某个拥有该方法的具体定义的类中,这个类定义了该方法的最终行为;
  3. 需要混入特质进行线性化计算的类,定义时不能立即混入特质,这样做会让编译器认为这个类是在重写末尾那个特质的方法。应该先定义这个类的子类来混入特质,然后构造子类的对象,或者直接用3.4.3所述方法快速构造子类对象;
  4. 特质对该方法的定义必须出现super.方法名(参数)
  5. 方法的执行顺序遵循线性化计算公式,起点是公式从左往右第一个特质,外部传入的参数由起点接收,起点的super.方法名(参数)会调用起点右边第一个特质的同名方法,并把起点的计算结果作为参数传递,以此类推。最后结果会回到最左边的类本身。
  6. 这个类实际上直接或间接重写或实现了基类的方法,如果定义中也出现了super.方法名(参数),则会调用它的上一层超类的实现版本。如果这个类没有重写,那就要有继承自超类的实现。

线性化计算公式:

  1. 最左边是类本身;
  2. 在类的右边写下定义时最后混入的那个特质,并接着往右按继承顺序写下该特质的所有超类和超特质;
  3. 继续往右写下倒数第二个混入的特质,以及其超类和超特质,直到写完所有特质;
  4. 所有重复项值保留最右边的那个,并在最右边加上AnyRefAny

现在我们编写这样的一个test.scala文件:

abstract class A {
  def m(s: String) : String
}

class X extends A {
  def m(s: String) = "X ->" + s
}

trait B extends A {
  abstract override def m(s: String) = super.m("B ->" + s)
}

trait C extends A {
  abstract override def m(s: String) = super.m("C ->" + s)
}

trait D extends A {
  abstract override def m(s: String) = super.m("D ->" + s)
}

trait E extends C {
  abstract override def m(s: String) = super.m("E ->" + s)
}

trait F extends C {
  abstract override def m(s: String) = super.m("F ->" + s)
}

class G extends X {
  override def m(s: String) = "G ->" + s
}

val x = new G with D with E with F with B
@main def test() = println(x.m("End"))

最终,需要混入特质进行线性化运算的类G在定义时没有立即混入特质,只是继承了classX,且通过new G with D with E with F with B构建了G的匿名子类的对象。类A是一个抽象类,类X实现了抽象方法m,类G重写了X的m,其余特质也用abstract override重写了m,这保证m最后会回到G。A的m返回类型“String”是必须的。

根据线性化计算公式,我们一步步进行计算。注意类X也就是这个类G继承的类不参与运算,最左边是类本身:G ->,在类的右边写下定义时最后混入的特质,然后往右按照继承顺序写下该特质所有的超类和超特质,全部写完后再写第二个混入的类,以此类推。因此第二个写下的是最后混入的特质B和它的超类:G -> B -> A接着写类F。以此类推,我们写出:

G -> B -> A -> F -> C -> A -> E -> C -> A -> D -> A

之后我们删除其中重复的部分:

G -> B -> F -> E -> C -> D -> A

之后补上AnyRefAny

G -> B -> F -> E -> C -> D -> A -> AnyRef -> Any

起点是B,传入“End”,B输出“B -> End”,之后再传给F,输出“F -> B -> End”,继续向右调用,最后到A时没有操作可以执行,转回G的m,最终得到运行结果是:

G ->D ->C ->E ->F ->B ->End

如果G的m也有super或没有重写,那么会调用X的m,导致最后最左边多一个X,如果在定义G时立即混入特质,则相当于普通的方法重写,如果上一层超类是抽象类,立即引入会报错。

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

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

相关文章

VuePress2配置unocss的闭坑指南

文章目录 1. 安装依赖:准备魔法材料2. 检查依赖版本一定要一致:确保魔法配方准确无误3. 新建uno.config.js:编写咒语书4. 配置config.js和client.js:完成仪式 1. 安装依赖:准备魔法材料 在开始我们的前端魔法之前&…

游戏引擎学习第77天

仓库: https://gitee.com/mrxiao_com/2d_game 回顾昨天的 bug 今天我们继续开发进度,进行调试昨天代码的问题,主要是关于如何跟踪玩家和敌人在世界中的高度位置。虽然我们做的是一款 2D 游戏,但我们希望能够处理多层的房间,玩家…

uniapp结合movable-area与movable-view实现拖拽功能2

前言 上篇我们写了&#xff0c;固定高度的拖拽&#xff0c;这篇我们将进行不固定高度的拖拽模块编写完成。 开始 一、初始化 我们在list数组里面增加一个data的动态数组&#xff0c;这样可以动态改变元素的高度。 当前元素y 上一个元素的高度 <template><view s…

ubuntu为Docker配置代理

终端代理 我们平常在ubuntu终端中使用curl或git命令时&#xff0c;往往会很慢。 所以&#xff0c;首先需要给ubuntu终端环境添加代理。 查看自身那个软件的端口号&#xff0c;我这里是7890。 sudo gedit ~/.bashrcexport http_proxyhttp://localhost:7890 export https_pr…

【Uniapp-Vue3】v-if条件渲染及v-show的选择对比

如果我们想让元素根据响应式变量的值进行显示或隐藏可以使用v-if或v-show 一、v-show 另一种控制显示的方法就是使用v-show&#xff0c;使用方法和v-if一样&#xff0c;为true显示&#xff0c;为false则不显示。 二、v-if v-if除了可以像v-show一样单独使用外&#xff0c;还…

wujie无界微前端框架初使用

先说一下项目需求&#xff1a;将单独的四套系统的登录操作统一放在一个入口页面进行登录&#xff0c;所有系统都使用的是vue3&#xff0c;&#xff08;不要问我为啥会这样设计&#xff0c;产品说的客户要求&#xff09; 1.主系统下载wujie 我全套都是vue3&#xff0c;所以直接…

C语言 数组编程练习

1.将数组A的内容和数组B中的内容进行交换。&#xff08;数组一样大&#xff09; 2.创建一个整形数组&#xff0c;完成对数组的操作 实现函数Init()初始化数组全为0 实现print()打印数组的每个元素 实现reverse()函数完成数组元素的逆置 //2.创建一个整形数组&#xff0c;完…

【three.js】模型-几何体Geometry,材质Material

模型 在现实开发中&#xff0c;有时除了需要用代码创建模型之外&#xff0c;多数场景需要加载设计师提供的使用设计软件导出的模型。此时就需要使用模型加载器去加载模型&#xff0c;不同格式的模型需要引入对应的模型加载器&#xff0c;虽然加载器不同&#xff0c;但是使用方式…

MySQL和Hive中的行转列、列转行

水善利万物而不争&#xff0c;处众人之所恶&#xff0c;故几于道&#x1f4a6; 文章目录 MySQL1.行转列2.列转行 Hive1.行转列2.列转行(1)侧窗(2)union MySQL 1.行转列 把多行转成列。直接group&#xff0c;sum(if()) 2.列转行 Hive 1.行转列 select name,sum(if(kmshuxu…

unity学习8:unity的基础操作 和对应shortcut

目录 1 unity的基础操作的工具&#xff0c;就在scene边上 1.1 对应shortcut快捷键 2 物体的重置/ 坐标归到0附近 3 F&#xff1a;快速找到当前gameobject 4 Q&#xff1a;小手和眼睛&#xff0c;在场景中移动 5 W&#xff1a;十字箭头&#xff0c;移动gameobject 6 …

对话|全年HUD前装将超330万台,疆程技术瞄准人机交互“第一屏”

2024年&#xff0c;在高阶智驾进入快速上车的同时&#xff0c;座舱人机交互也在迎来新的增长点。Chat GPT、AR-HUD、车载投影等新配置都在带来新增量机会。 高工智能汽车研究院监测数据显示&#xff0c;2024年1-10月&#xff0c;中国市场&#xff08;不含进出口&#xff09;乘用…

Openwrt @ rk3568平台 固件编译实践(二)- ledeWRT版本

目录 ledeWRT介绍固件编译下载代码修改feed源更新并安装编译第三方软件包制作用于eMMC烧写的rootfs基于lede发行版验证烧写rk3568.img, LEDE wrt启动成功refhttps://blog.csdn.net/zc21463071/article/details/106751361介绍rk3568平台下, lede 大神版 openwrt固件的下载、编译…

【Unity3D】Text文本文字掉落效果

相关技术&#xff1a;Text、TextMesh、Rigidbody&#xff08;刚体&#xff09;、BoxCollider&#xff08;碰撞体&#xff09;、TextGenerator、文本网格、文字网格 原理&#xff1a;使用UGUI Text获取其文字的每个字符网格坐标&#xff0c;转世界坐标生成对应的3D文本(TextMesh…

Spring Boot教程之四十九:Spring Boot – MongoRepository 示例

Spring Boot – MongoRepository 示例 Spring Boot 建立在 Spring 之上&#xff0c;包含 Spring 的所有功能。由于其快速的生产就绪环境&#xff0c;使开发人员能够直接专注于逻辑&#xff0c;而不必费力配置和设置&#xff0c;因此如今它正成为开发人员的最爱。Spring Boot 是…

el-table-fixed滚动条被遮挡导致滚动条无法拖动

/* 设置默认高度-滚动条高度 */ .el-table__fixed { height: calc(100% - 16px) !important; } .el-table__fixed {height: calc(100% - 16px) !important; } .el-table__fixed:before {height: 0px; }

探索大型语言模型新架构:从 MoE 到 MoA

探索大型语言模型新架构&#xff1a;从 MoE 到 MoA 当前&#xff0c;商业科技公司纷纷投身于一场激烈的竞赛&#xff0c;不断扩大语言模型的规模&#xff0c;并为其注入海量的高质量数据&#xff0c;试图逐步提升模型的准确性。然而&#xff0c;这种看似顺理成章的发展路径逐渐…

【通识安全】煤气中毒急救的处置

1.煤气中毒的主要症状与体征一氧化碳中毒&#xff0c;其中毒症状一般分为轻、中、重三种。 (1)轻度&#xff1a;仅有头晕、头痛、眼花、心慌、胸闷、恶心等症状。如迅速打开门窗&#xff0c;或将病人移出中毒环境&#xff0c;使之吸入新鲜空气和休息&#xff0c;给些热饮料&am…

分享:osgb倾斜数据转cesium-3dtiles 小工具.

背景: 很多知识殊途同归,在三维软件这块,少不了要和各种各样的数据格式打交道.osgb,stl,obj,3dtiles,3ds等等..虽然里面本质核心基本都是几何数据拓扑数据材质纹理数据等等,但是由于其组织方式不同和特殊的应用场景,导致很多模型需要转来转去...相信很多人在这方面都或多或少吃…

Node.js——fs(文件系统)模块

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1f4c3;个人状态&#xff1a; 研发工程师&#xff0c;现效力于中国工业软件事业 &#x1f680;人生格言&#xff1a; 积跬步…

Mac M2基于MySQL 8.4.3搭建(伪)主从集群

前置准备工作 安装MySQL 8.4.3 参考博主之前的文档&#xff0c;在本地Mac安装好MySQL&#xff1a;Mac M2 Pro安装MySQL 8.4.3安装目录&#xff1a;/usr/local/mysql&#xff0c;安装好的MySQL都处于运行状态&#xff0c;需要先停止MySQL服务最快的方式&#xff1a;系统设置 …