当前位置: 首页 > news >正文

[读书日志]从零开始学习Chisel 第十三篇:Scala的隐式参数与隐式转换(敏捷硬件开发语言Chisel与数字系统设计)

10. 隐式转换与隐式参数

假设编写了一个向量类MyVector,并且包含一些向量的基本操作。因为向量可以与标量做数乘运算,所以需要一个计算数乘的方法“*”,它应该接收一个类型为基本值类的参数,在向量对象myVec调用该方法时,可以写成myVec * 2的形式。在数学中,反过来写2 * myVec也是可行的,但在程序中不行。操作符左边是调用对象,反过来写就表示Int对象2是方法的调用者,但是Int类中并没有这种方法。

为了解决上述问题,所有oop语言都会有相应的措施,C++采用友元,Scala采取名为隐式转换的策略,把原来的Int类对象2转换类型,变成MyVector类的对象,这样它就能使用数乘方法。隐式转换属于隐式定义的一种,它将程序员事先写好的定义,允许编译器隐式地插入这些定义来解决类型错误。

10.1 隐式定义的规则

隐式定义有如下约束规则:

  1. 标记规则:只有用关键字implicit标记的定义才能被编译器隐式使用,任何函数,变量或单例对象都可以被标记。其中,标记为隐式的变量和单例对象常用作隐式参数。隐式的函数常用于隐式转换。比如x + y由于x类型错误不能通过编译,编译器会将代码改成convert(x) + y,其中convert是某种可用的隐式转换。如果convert能把x改成某种支持+方法的对象,那么这段代码就可以通过类型检查;
  2. 作用域规则:Scala编译器只会考虑当前作用域内的隐式定义,隐式定义在当前作用域必须是单个标记符,编译器不会展开成A.convert(x) + y的形式,有一个例外是编译器会在与隐式转换相关的源类型和目标类型的伴生对象中查找隐式定义,因此常在伴生对象中定义隐式转换,而不需要显式导入;
  3. 每次一个规则:编译器只会插入一个隐式定义,不会出现convert1(convert2(x)) + y这种嵌套的形式;
  4. 显式优先规则:如果显式定义能通过类型检查,就不必进行隐式转换。

Scala只会在三个地方使用隐式定义:转换到一个预期的类型,转换某个选择接收端,隐式参数。

10.2 隐式地转换到期望类型

Scala编译器对于类型检查比较严格,比如一个浮点数赋值给整数变量,人们可能希望通过截断小数部分完成赋值,但是Scala默认情况下不允许这种丢失精度的转换。可以定义一个隐式转换来完成:

scala> import scala.language.implicitConversionsscala> implicit def doubleToInt(x: Double) : Int = x.toInt
def doubleToInt(x: Double): Intscala> val i: Int = 1.5
val i: Int = 1scala> val i: Int = doubleToInt(2.33)
val i: Int = 2
10.3 隐式地转换接收端

接收端就是指调用方法或字段的对象,调用对象在非法的情况下,被隐式转换成了合法的对象,这是隐式转换最常用的地方。

scala> class MyInt(val i: Int)
// defined class MyIntscala> 1.i
-- [E008] Not Found Error: ---------------------------------------------------------------------------------------------
1 |1.i|^^^|value i is not a member of Int
1 error foundscala> implicit def intToMy(x: Int): MyInt = new MyInt(x)
def intToMy(x: Int): MyIntscala> 1.i
val res0: Int = 1

在定义隐式转换前,Int类没有i字段,所以调用会报错,定义隐式转换后,用一个Int对象构造了一个新的MyInt对象,而MyInt对象就有字段i。1.i被编译器隐式展开成intToMy(1).i

隐式转换因此经常用于模拟新的语法,比如Chisel中大量使用了隐式定义。

映射的键-值对语法键->值其实是一个对偶(键,值),也是隐式转换起作用。

10.4 隐式类

隐式类是一个以关键字implicit开头的类,用于简化富包装类的编写。它不能是样例类,并且主构造方法有且仅有一个参数。此外,隐式类只能位于某个单例对象、类或特质中,不能单独出现在顶层。隐式类的特点是让编译器在相同层次下自动生成一个与类名相同的隐式转换,该转换接受一个与隐式类的主构造方法相同的参数,并用这个参数构造一个隐式类的实例对象来返回。

10.5 隐式参数

函数的最后一个参数列表可以用关键字implicit声明为隐式的,这样整个参数列表的参数都是隐式参数。注意,是整个参数列表,即使括号中有多个参数,也只需要在开头写一个implicit,每个参数都是隐式的,不存在部分隐式部分显式。

当调用函数时,若缺省了隐式参数列表,则编译器尝试插入相应的隐式定义。也可以显式给出参数,但是必须全部缺省或者全部写出,不能只写出一部分。

要让编译器隐式插入参数,就必须实现定义好符合预期类型的隐式变量,隐式单例对象和隐式函数,这些隐式定义也必须用implicit修饰。隐式变量,单例对象,函数在当前作用域的引用必须满足单标识符原则,即不同层次之间需要用import解决。

隐式参数的类型应该是稀有或特定的,类型名称最好能表明该参数的作用,而不是使用Int,String等已经约定好的名称。

class PreferredPrompt(val preference: String)
class PreferredDrink(val preference: String)object Greeter {def greet(name: String)(implicit prompt: PreferredPrompt, drink: PreferredDrink) = {println("Welcome, " + name + ". The system is ready.")print("But while you work, ")println("why not enjoy a cup of " + drink.preference + "?")println(prompt.preference)}
}object JoesPrefs {implicit val prompt: PreferredPrompt = new PreferredPrompt("Yes, master> ")implicit val drink: PreferredDrink = new PreferredDrink("tea")
}

保存后执行编译指令,并进入解释器,执行命令:

jia@J-MateBookEGo:~/scala_test$ scalac test.scala
jia@J-MateBookEGo:~/scala_test$ scala
Jan 13, 2025 1:09:02 PM org.jline.utils.Log logr
Welcome to Scala 3.6.2 (21.0.5, Java OpenJDK 64-Bit Server VM).
Type in expressions for evaluation. Or try :help.scala> :load test.scala
// defined class PreferredPrompt
// defined class PreferredDrink
// defined object Greeter
// defined object JoesPrefsscala> Greeter.greet("Joe")
-- [E172] Type Error: --------------------------------------------------------------------------------------------------
1 |Greeter.greet("Joe")|                    ^|        No given instance of type PreferredPrompt was found for parameter prompt of method greet in object Greeter||        The following import might fix the problem:||          import JoesPrefs.prompt|
1 error foundscala> import JoesPrefs._scala> Greeter.greet("Joe")
Welcome, Joe. The system is ready.
But while you work, why not enjoy a cup of tea?
Yes, master>scala> Greeter.greet("Joe")(prompt, drink)
Welcome, Joe. The system is ready.
But while you work, why not enjoy a cup of tea?
Yes, master>
10.6 含有隐式参数的主构造方法

普通的函数可以含有隐式参数,类的主构造方法也可以包含隐式参数,辅助构造方法不允许出现隐式参数。假设类A仅有一个参数列表,并且该列表是隐式的,那么A的实际定义形式是A()(implicit 参数),也就是比字面上的代码多了一对空括号,无论用new实例化类A,还是被其他类继承,若调用主构造方法时显式地给出隐式参数,就必须写出这对空括号,若隐式参数是编译器自动插入,则空括号可有可无。

scala> class A(implicit val x: Int)
// defined class Ascala> val a = new A(1)
-- Error: --------------------------------------------------------------------------------------------------------------
1 |val a = new A(1)|              ^|              too many arguments for constructor A in class A: ()(implicit x: Int): A
1 error foundscala> val a = new A()(1)
val a: A = A@6caeba36scala> implicit val ORZ = 233
-- Error: --------------------------------------------------------------------------------------------------------------
1 |implicit val ORZ = 233|             ^|             type of implicit definition needs to be given explicitly
1 error foundscala> implicit val ORZ: Int = 233
val ORZ: Int = 233scala> val b = new A
val b: A = A@6a7aa675scala> b.x
val res0: Int = 233scala> val c = new A()
val c: A = A@1534bdc6scala> c.x
val res1: Int = 233

相关文章:

[读书日志]从零开始学习Chisel 第十三篇:Scala的隐式参数与隐式转换(敏捷硬件开发语言Chisel与数字系统设计)

10. 隐式转换与隐式参数 假设编写了一个向量类MyVector,并且包含一些向量的基本操作。因为向量可以与标量做数乘运算,所以需要一个计算数乘的方法“*”,它应该接收一个类型为基本值类的参数,在向量对象myVec调用该方法时&#xf…...

CMake学习笔记(1)

1. CMake概述 CMake 是一个项目构建工具,并且是跨平台的。关于项目构建我们所熟知的还有Makefile(通过 make 命令进行项目的构建),大多是IDE软件都集成了make,比如:VS 的 nmake、linux 下的 GNU make、Qt …...

cursor+deepseek构建自己的AI编程助手

文章目录 准备工作在Cursor中添加deepseek 准备工作 下载安装Cursor (默认安装在C盘) 注册deepseek获取API key 在Cursor中添加deepseek 1、打开cursor,选择设置 选择Model,添加deepseek-chat 注意这里去掉其他的勾选项&…...

Kotlin实现DataBinding结合ViewModel的时候,提示找不到Unresolved reference: BR解决方案

在用Kotlin语言实现DataBinding结合ViewModel的代码的时候,如下所示: class UserModel(private val userName: String, private val userAge: Int) : BaseObservable() {get:Bindablevar name: String userNameset (value) {field valuenotifyPropert…...

java项目启动时,执行某方法

1. J2EE项目 在Servlet类中重写init()方法,这个方法会在Servlet实例化时调用,即项目启动时调用。 import javax.servlet.ServletException; import javax.servlet.http.HttpServlet;public class MyServlet extends HttpServlet {Overridepublic void …...

详解如何自定义 Android Dex VMP 保护壳

版权归作者所有,如有转发,请注明文章出处:https://cyrus-studio.github.io/blog/ 前言 Android Dex VMP(Virtual Machine Protection,虚拟机保护)壳是一种常见的应用保护技术,主要用于保护 And…...

Grails应用http.server.requests指标数据采集问题排查及解决

问题 遇到的问题:同一个应用,Spring Boot(Java)和Grails(Groovy)混合编程,常规的Spring Controller,可通过Micromete Pushgateway, 采集到http.server.requests指标数据,注意下面的指标名称是点号&#…...

开源临床试验软件OpenClinica的安装

本文是为帮网友 A萤火虫 解决安装问题做的记录; 简介 什么是 OpenClinica ? OpenClinica 是世界上第一个商业开源临床试验软件,主要用于电子数据捕获(EDC)和临床数据管理(CDM)。它的设计旨在优…...

网络安全 | 网络安全法规:GDPR、CCPA与中国网络安全法

网络安全 | 网络安全法规:GDPR、CCPA与中国网络安全法 一、前言二、欧盟《通用数据保护条例》(GDPR)2.1 背景2.2 主要内容2.3 特点2.4 实施效果与影响 三、美国《加利福尼亚州消费者隐私法案》(CCPA)3.1 背景3.2 主要内…...

深入学习 Python 爬虫:从基础到实战

深入学习 Python 爬虫:从基础到实战 前言 Python 爬虫是一个强大的工具,可以帮助你从互联网上抓取各种数据。无论你是数据分析师、机器学习工程师,还是对网络数据感兴趣的开发者,爬虫都是一个非常实用的技能。在本文中&#xff…...

element plus 使用 upload 组件达到上传数量限制时隐藏上传按钮

最近在重构项目,使用了 element plus UI框架,有个功能是实现图片上传,且限制只能上传一张图片,结果,发现,可以限制只上传一张图片,但是上传按钮还在,如图: 解决办法&…...

音频DSP的发展历史

音频数字信号处理(DSP)的发展历史是电子技术、计算机科学和音频工程共同进步的结果。这个领域的进展不仅改变了音乐制作、音频后期制作和通信的方式,也影响了音频设备的设计和功能。以下是对音频DSP发展历史的概述: 早期概念和理论…...

2025低代码与人工智能AI新篇

在当今数字化浪潮汹涌澎湃的时代,低代码开发与人工智能(AI)犹如两颗璀璨的星辰,正逐渐交汇融合,为企业解锁前所未有的智能业务解决方案。今天,咱们就深入探讨一下低代码平台是如何集成 AI 技术,…...

【HarmonyOS Next NAPI 深度探索1】Node.js 和 CC++ 原生扩展简介

【HarmonyOS Next NAPI 深度探索1】Node.js 和 CC 原生扩展简介 如果你用过 Node.js,应该知道它强大的地方在于能处理各种场景,速度还很快。但你有没有想过,Node.js 的速度秘密是什么?今天我们来聊聊其中一个幕后英雄——原生扩展…...

redis的学习(四)

13. 渐进式遍历 通过渐进式遍历能够获取当前所有的key,又不会讲当前的服务器卡死。不是一个命令将所有的key获取,而是每执行一次命令,只获取到其中的一部分。所以想要获取到所有的key就需要多次遍历,即化整为零的思想。 渐进式遍历…...

C# winform 多线程 UI更新数据 报错:无法访问已释放的对象。

System.ObjectDisposedException HResult0x80131622 Message无法访问已释放的对象。 ObjectDisposed_ObjectName_Name SourceSystem.Windows.Forms StackTrace: at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, …...

error: linker `link.exe` not found

开始学习rust,安装好rust的环境,开始从hello world开始,结果用在win10环境下,使用vs code或cmd窗口编译rust报错: PS E:\study_codes\rust-demo\chart01> rustc hello.rs error: linker link.exe not found| note:…...

Vue.js组件开发-如何使用moment.js

在Vue.js组件开发中,需要处理日期和时间,moment.js 是一个非常有用的库。moment.js 提供了丰富的API来解析、验证、操作和显示日期和时间。 步骤: 1. 安装moment.js 首先,需要通过npm或yarn安装moment.js。在项目根目录下运行以…...

Linux第二课:LinuxC高级 学习记录day01

0、大纲 0.1、Linux 软件安装,用户管理,进程管理,shell 命令,硬链接和软连接,解压和压缩,功能性语句,结构性语句,分文件,make工具,shell脚本 0.2、C高级 …...

《DOM NodeList》

《DOM NodeList》 介绍 DOM(文档对象模型)是HTML和XML文档的编程接口,它允许开发者在JavaScript等编程语言中操作文档的结构、样式和内容。在DOM中,NodeList是一个重要的接口,它表示一个包含节点(如元素、…...

超短脉冲激光自聚焦效应

前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...

java 实现excel文件转pdf | 无水印 | 无限制

文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...

(二)原型模式

原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

3403. 从盒子中找出字典序最大的字符串 I

3403. 从盒子中找出字典序最大的字符串 I 题目链接:3403. 从盒子中找出字典序最大的字符串 I 代码如下: class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)

漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...

STM32HAL库USART源代码解析及应用

STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...

【Linux系统】Linux环境变量:系统配置的隐形指挥官

。# Linux系列 文章目录 前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变量的生命周期 四、环境变量的组织方式五、C语言对环境变量的操作5.1 设置环境变量:setenv5.2 删除环境变量:unsetenv5.3 遍历所有环境…...

Chromium 136 编译指南 Windows篇:depot_tools 配置与源码获取(二)

引言 工欲善其事,必先利其器。在完成了 Visual Studio 2022 和 Windows SDK 的安装后,我们即将接触到 Chromium 开发生态中最核心的工具——depot_tools。这个由 Google 精心打造的工具集,就像是连接开发者与 Chromium 庞大代码库的智能桥梁…...

pgsql:还原数据库后出现重复序列导致“more than one owned sequence found“报错问题的解决

问题: pgsql数据库通过备份数据库文件进行还原时,如果表中有自增序列,还原后可能会出现重复的序列,此时若向表中插入新行时会出现“more than one owned sequence found”的报错提示。 点击菜单“其它”-》“序列”,…...

Django RBAC项目后端实战 - 03 DRF权限控制实现

项目背景 在上一篇文章中,我们完成了JWT认证系统的集成。本篇文章将实现基于Redis的RBAC权限控制系统,为系统提供细粒度的权限控制。 开发目标 实现基于Redis的权限缓存机制开发DRF权限控制类实现权限管理API配置权限白名单 前置配置 在开始开发权限…...