第十五章 Scala进阶——隐式转换与隐式参数

2023-10-27

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

为了解决上述问题,所有的oop语言都会有相应的策略,比如笔者熟悉的C++是通过友元的方式来解决。Scala则是采取名为“隐式转换”的策略,也就是把本来属于Int类的对象“2”转换类型,变成MyVector类的对象,这样它就能使用数乘方法。隐式转换属于隐式定义的一种,隐式定义就是那些程序员事先写好的定义,然后允许编译器隐式地插入这些定义来解决类型错误。因为这部分定义通常对使用者不可见,并且由编译器自动调用,故而得名“隐式定义”。

一、隐式定义的规则

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

①标记规则。只有用关键字“implicit”标记的定义才能被编译器隐式使用,任何函数、变量或单例对象都可以被标记。其中,标记为隐式的变量和单例对象常用作隐式参数,隐式的函数常用于隐式转换。比如,代码“x + y”因为调用对象x的类型错误而不能通过编译,那么编译器会尝试把代码改成“convert(x) + y”,其中convert是某种可用的隐式转换。如果convert能将x改成某种支持“+”方法的对象,那么这段代码就可能通过类型检查。

②作用域规则。Scala编译器只会考虑在当前作用域内的隐式定义,否则,所有隐式定义都是全局可见的将会使得程序异常复杂甚至出错。隐式定义在当前作用域必须是“单个标识符”,即编译器不会展开成“A.convert(x) + y”的形式。如果想用A.convert,那么必须先用“import A.convert”导入才行,然后被展开成“convert(x) + y”的形式。单个标识符规则有一个例外,就是编译器会在与隐式转换相关的源类型和目标类型的伴生对象里查找隐式定义。因此,常在伴生对象中定义隐式转换,而不用在需要时显式导入。

③每次一个规则。编译器只会插入一个隐式定义,不会出现“convert1(convert2(x)) + y”这种嵌套的形式,但是可以让隐式定义包含隐式参数来绕开这个限制。

④显式优先原则。如果显式定义能通过类型检查,就不必进行隐式转换。因此,总是可以把隐式定义变成显式的,这样代码变长但是歧义变少。用显式还是隐式,需要取舍。

此外,隐式转换可以用任意合法的标识符来命名。有了名字后,一是可以显式地把隐式转换函数写出来,二是明确地导入具体的隐式转换而不是导入所有的隐式定义。

Scala只会在三个地方使用隐式定义:转换到一个预期的类型,转换某个选择接收端(即调用方法或字段的对象),隐式参数。

二、隐式地转换到期望类型

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

scala> val i: Int = 1.5
<console>:11: error: type mismatch;
 found   : Double(1.5)
 required: Int
       val i: Int = 1.5
                    ^

但是用户可能并不关心精度问题,确实需要这样一种赋值操作,那么就可以通过定义一个隐式转换来完成。例如:

scala> import scala.language.implicitConversions
import scala.language.implicitConversions

scala> implicit def doubleToInt(x: Double) = x.toInt
doubleToInt: (x: Double)Int

scala> val i: Int = 1.5
i: Int = 1 

此时再进行之前的赋值,就会正确地截断小数部分。当然,隐式转换也可以显式地调用:

scala> val i: Int = doubleToInt(2.33)
i: Int = 2 

第七章讲解类继承时,最后提到了Scala的全局类层次,其中就有七种基本值类的转换,比如Int可以赋值给Double。这其实也是隐式转换在起作用,只是这个隐式转换定义在scala包里的单例对象Predef里。因为所

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

第十五章 Scala进阶——隐式转换与隐式参数 的相关文章

随机推荐

  • 最新RAD Studio 11.3亚历山大版本上市

    By Marco Cantu February 27 2023 Embarcadero很高兴地宣布RAD Studio 11 Alexandria Release 3的发布 也被称为RAD Studio 11 3 同时发布的还有Delphi
  • k8s集群PHP环境使用

    一 环境介绍 k8s版本 1 15 2 存储 阿里云NAS 测试代码 wordpress 二 下载wordpress和创建好数据库等 1 下载wordpress wget https cn wordpress org latest zh C
  • 异步的AsyncHttpClient使用详解

    背景 前面的一篇文章 同步的HttpClient使用详解 中 提到了服务端通进行网络请求的方式 也讲述了在并发量大的情况下使用HttpClient的连接池来提高性能 此方法虽然很有效果 但是当访问量极大或网络不好的情况下也会出现某些网络请求
  • HyperLPR车牌识别技术算法之车牌粗定位与训练

    关于HyperLPR HyperLPR是一个使用深度学习针对对中文车牌识别的实现 与较为流行的开源的EasyPR相比 它的检测速度和鲁棒性和多场景的适应性都要好于目前开源的EasyPR HyperLPR可以识别多种中文车牌包括白牌 新能源车
  • js分享功能

    需求 页面需要添加分享到 微博 QQ空间 等功能 具体 div class jz blog a class jiathis button qzone QQ空间 a a class jiathis button tsina 新浪微博 a a
  • Cocos Creator性能调优优化集锦

    前言 一 为什么要做性能优化 性能 是一种优秀的能力 唤醒快 运行持久 稳定 这种能力在游戏上能让你的用户感觉很爽 表征表现为加载快 手机不发热 运行流畅 不卡顿 所以 性能优化的终极目标是 让你的用户感觉很爽 当然这种爽你不能以牺牲自己为
  • Docker快速部署Hadoop环境

    Docker安装部署Hadoop环境 通过三个容器来模拟三个节点 最后只保留Master节点实现搭建 安装环境 Ubuntu 22 04 1 LTS 和Docker 23 0 1 安装过程 拉取镜像 docker pull registry
  • 计算机视觉初步认识

    计算机视觉是使用计算机及相关设备对生物视觉的一种模拟 它的主要任务就是通过对采集的图片或视频进行处理以获得相应场景的三维信息 就像人类和许多其他类生物每天所做的那样 从计算机视觉领域可以衍生出大量有用的应用程序 下面是计算机视觉应用程序的一
  • FreeRTOS记录(八、用软件定时器?还是硬件定时器?)

    FreeRTOS软件定时器 相对前面的内容来说 软件定时器还是比较简单的 我们简单测试一下 因为是简单介绍 所以原理和源码的分析不会那么详细 具体可以根据文中API查看源码 使用起来记住创建 启动 回调函数核心步骤即可 增加测试Demo 再
  • 禁止 Cookie 使用 Session,采用 URL 重写,具体解决方案

    先叙述一下 session 的实现原理吧 session 服务器为每个客户端访问开辟的一块内存区域 可以存放一些客户端的一些操作信息 正常情况下在用户通过客户端访问服务器这个过程中 session 一直存活 直到客户端关闭 服务器中的 se
  • TWS耳机充电盒芯片方案、霍尔开关+无线充接收带电量显示方案

    旭鑫胜电子TWS充电盒方案XS016 RX 专门为TWS充电盒设计的无线充电接收方案XS016 RX XS016 RX无线充电接收芯片与锂电池充电管理芯片结合 以满足无线充电盒的设计要求 功能特点 1 符合qi1 2标准协议 2 具有异物检
  • CentOS-6.6-x86_64-minimal.iso镜像下载

    链接 https pan baidu com s 1FKfIvK65KzVxV96Gns7ivA https pan baidu com s 1FKfIvK65KzVxV96Gns7ivA 提取码 zt88
  • 2.1python程序控制-选择结构

    第1关 判断奇偶 任务描述 本关任务 编写一个能判断输入数字奇偶的小程序 相关知识 为了完成本关任务 你需要掌握 python如何进行数字的读取和if else条件控制结构 Begin your code here x int input
  • NNDL 实验五 前馈神经网络(1)二分类任务

    pytorch实现 4 1 神经元 4 1 1 净活性值 使用pytorch计算一组输入的净活性值z 净活性值z经过一个非线性函数f 后 得到神经元的活性值a 使用pytorch计算一组输入的净活性值 代码参考paddle例题 import
  • Hexo_更换主题(Next)

    Hexo 更换主题 Next Hexo更换主题 只需要将主题文件拷贝到自己博客根目录下的themes子目录内 然后修改配置文件 即可将hexo默认的主题更换为自己想要的主题 下载Next 打开git bash here命令提示符 执行 cd
  • 初体验深信服的云桌面

    昨天上午深信服的工程师到这边来安装服务器 本想看一下具体的安装 但是上午有其他事情 没有看成 下午他给我讲了一下具体的使用 我体验了一下深信服的云桌面 总体感觉管理员的维护和客户的使用都比较方便 但是可能是服务器的配置一般 体验谈不上顺滑
  • react的生命周期

    目录 一 初始化阶段 constructor static getDerivedStateFromProps componentWillMount UNSAFE componentWillMount render componentDidM
  • pg_dump 不能用 出现pg_dump: No matching tables were found,pg_dump: schema with OID 1515227 does not exi

    使用sql查询 创建函数 直接复制即可 CREATE OR REPLACE FUNCTION public show create table in schema name varchar in table name varchar RET
  • 初步了解爆破(附Burp suite)

    huihui爆破通常是网站管理 运营人员由于安全意识不足 为了方便 避免忘记密码等 使用了非常容易记住的密码 或者是直接采用了系统的默认密码等 攻击者利用此漏洞可直接进入应用系统或者管理系统 从而进行系统 网页 数据的篡改与删除 非法获取系
  • 第十五章 Scala进阶——隐式转换与隐式参数

    考虑如下场景 假设编写了一个向量类MyVector 并且包含了一些向量的基本操作 因为向量可以与标量做数乘运算 所以需要一个计算数乘的方法 它应该接收一个类型为基本值类的参数 在向量对象myVec调用该方法时 可以写成诸如 myVec 2