`
beike
  • 浏览: 355811 次
社区版块
存档分类
最新评论

cala中隐式转换(implicit conversion)的优先顺序

阅读更多

转 http://blog.csdn.net/nethibernate/article/details/5893184

在学习Scala的时候,隐式转换(implicit conversion)这个特性让我实在是闹不住啊。于是乎一边试用一边感慨:真的是太强大,太方便了。

不过,越是强大且方便的东西,越容易用出毛病来。在我不求甚解的情况下,毛病就来了,我把它称为隐式转换优先顺序问题:

 

假设我们有一个表示文本的行数的类LineNumber:

 

class LineNumber ( val num : Int ) 

 

我们可以用这个类来表示一本书中每一页的行数:

 

val lineNumOfPage1 = new LineNumber(112)
val lineNumOfPage2 = new LineNumber(120)


上面的代码分别表示了第一页和第二页的行数。当然,我们也应该可以将它们相加,得到这两页的总行数:

val totalLineNum = lineNumOfPage1 + lineNumOfPage2

 

这样的话,我们的LineNumber类里就应该有一个 “+” 方法来将两个对象相加:

 

class LineNumber ( val num : Int ) {
  
  def + ( that : LineNumber ) = new LineNumber( this.num + that.num )

}


从直观上讲,我们甚至可以直接用整数来和LineNumber相加:

val totalLineNumber = lineNumOfPage1 + 120

//或者

val totalLineNumber = 112 + lineNumOfPage2

 

写到这里我们发现,LineNumber对象中没有接受整型作为参数的 “+” 方法;而整型中也不会有接受LineNumber作为参数的 “+” 方法。

 

为了说明问题,我们不在LineNumber类中增加一个整型作为参数的重载方法,而是定义两个隐式转换,一个将Int转换为LineNumber,另一个将LineNumber转换为Int:

 

object LineNumber{
  
  implicit def intToLineNumber( i : Int ) = new LineNumber(i)

  implicit def lineNumberToInt( o : LineNumber ) = o.num

}


接下来再让我们尝试用LineNumber和整型相加:

import LineNumber._

val totalLineNumber1 = lineNumOfPage1 + 120

val totalLineNumber2 = 112 + lineNumOfPage2


我们会得到什么结果呢?

我最初认为,Scala编译器可能会产生编译错误,毕竟我们现在的代码中对于两种类型的隐式转换都是存在的,这样的话上面两个语句的方法参数和调用方法的对象都可以做隐式转换。很明显我错了。运行结果:totalLineNumber1是一个新的LineNumber的对象,并且它的字段num会是232;而totalLineNumber2则是一个Int类型,值为232。

先让我们看看在编译时加入 “-Xprint:typer” 后上面两句的结果:

 

val totalLineNumber1: LineNumber = lineNumOfPage1.+(LineNumber.intToLineNumber(120));

val totalLineNumber2: Int = 112.+(LineNumber.lineNumberToInt(lineNumOfPage2));


到这里已经很清楚了。Scala编译器优先选择了方法的参数作为转换对象,而没有选择调用方法的对象。这是为什么呢?

其实,当程序类型检查出现问题的时候,Scala编译器会在两个位置上对出现问题的语句尝试使用隐式转换:

 

  • 第一个位置是 “可以直接将某个类型转换为期望的类型” 的地方
  • 第二个位置是 “可以将调用方法的对象转换为合适类型” 的地方


第一个位置是那种我们需要A但是传入的却是B的地方。上面的例子正好就是这样的情况,对于totalLineNumber1来说,lineNumOfPage1的 “+” 方法需要的参数类型是LineNumber型,然而我们传入的是Int类型,Scala编译器在这里检测到类型错误后,会寻找将Int转换为LineNumber的隐式转换。因为在代码开始时,我们利用 "import LineNumber._ " 导入了相应的隐式转换,因此Scala编译器使用导入的隐式转换将整型120转换为了LineNumber类型。totalLineNumber2发生的情况是相同的,只不过是将LineNumber类型转换为了Int类型。

也就是说,Scala编译器在使用隐式转换的时候,首先回去寻找可以直接转换类型的位置,其次才对调用方法的对象。如果我们将我们的隐式转换中intToLineNumber的转换去掉,那么我们得到的totalLineNumber1就会变为一个整型。


就像我开头所说的那样,Scala的隐式转换是一个非常强大的工具,但是如果不了解它,或者将其滥用在程序中,会使得程序难以理解和维护。真的到了那个时候,就确实“闹不住”了。

 

分享到:
评论

相关推荐

    S3cala:为Scala编写的非阻塞S3客户端

    S3cala Scala的非阻塞S3客户端用法该项目尚未投入生产; 使用风险自负。用法示例在内部,S3cala是AWS Java SDK的精简包装。 它使异步API适应使用Scala的 ,从而使其易于使用。 package org . example . s3calaimport...

    alg-net-cala-config:Net-Installer的Calamares配置

    alg-pure-cala-config

    微机原理电科

    微机原理的期末考试试卷

    白光LED用红色发光材料CaLa2(MoO4)4:Eu3+的微波辅助溶胶–凝胶法合成及发光特性 (2015年)

    以柠檬酸为络合剂,采用微波辅助溶胶–凝胶法制备了CaLa2(MoO4)4:Eu3+红色荧光粉。研究了前驱体的热分解历程,分析表征了样品的结构、形貌和发光性能。探讨了焙烧温度、Eu3+掺杂量、柠檬酸与乙二醇摩尔比和硼酸用量等...

    Python_Midterm_Cala:Python中期存储库-Petr Chala-2021_06_04

    Python_Midterm_Cala Python中期存储库-PetrČala-2021_06_04 这是PetrČala编写和提交的Python数据处理-JEM207(LS2020 / 21)代码主题中期的存储库

    scala-2.11.12.msi 安装程序

    Scala是一门多范式的编程语言,一种类似java的编程语言,设计初衷是实现可伸缩的语言、并集成面向对象编程和函数式编程的各种特性。 此为安装程序

    微信dat文件解密还原工具【易语言】【含源代码】【含模块】

    【说明】电脑版微信用了一段时间之后,会在硬盘中存储大量以*.dat为扩展名存储的图像加密文件,占用了大量的空间。微信本身不提供甄别和删除这些图片文件的功能,因此编制一个可以将这些加密dat文件解密的程序,并将...

    adi-与平台无关的应用程序的超便携式硬件接口-Rust开发

    Blog Cala旨在成为Rust中bo Make便携式应用和视频游戏的“氧化重新实现”。 关于| 来源| 变更日志| 教程| Blog Cala旨在成为Flutter / GTK和SDL /其他SDL项目在一个库中的“氧化重新实现”! Flutter主要用于移动...

    ELISACalc.rar

    ELISA Calc工具,可以生成直线回归、二次三次曲线回归、logistic曲线拟合、三次样条插值等拟合曲线图,也可用于X计算Y和Y计算X,和A、B、C、D,R^2值

    scala-2.12.10.msi

    scala-2.12.10.msi 大数据编程语言

    babel-plugin-transform-scala-lambda:启用Scala lambda样式

    转换Scala lambda 启用S​​cala Lambda样式 动机 对于简单的事情,允许使用更简洁的语法。 Scala是一门很棒的语言(您应该看看 ) 安装 npm install --save-dev babel-plugin-transform-scala-lambda 用法 将以...

    ELISA Calc(带说明链接)

    ELSA Calc软件,带使用说明链接,亲测拟合效果很好,尤其是四参数曲线拟合非常棒,故分享给大家下载

    ELISACalc(拟合数据软件)

    ELISACalc(拟合数据软件)

    TEC-XP16计算机组成原理实验

    D组:基本指令 CALA 扩展指令 IRET 这种分类办法,是为了突出指令执行步骤的划分结果,有利于讲解控制器设计技术。 A组指令完成的是通用寄存器之间的数据运算或传送,或其它几项特殊的操作,在取指之后可一步完成。 ...

    java原生黄瓜影视源码-JavaFinal:JavaFinal

    java原生Cucumber影视源码 史诗巨制悬疑历史动作大片——Battle 一、 剧情台本 葫芦七兄弟初始乱序->按长蛇阵依序排队 按下←↑→↓方向键/...葫芦兄弟还需要排序,所以有些额外的属性(如顺序seq等),因此定义Cala

    李金优-时间积分1

    引入t,需在各增量步进行循环计算;载荷阵与时间有关需要修改。所以,总体上stap90程序增加了cala计算初始加速度,修改plane.for计算单元M,C阵,增

    光网络 多维光网络

    ECI 从SONET/SDH 技术面市的那一刻起就一直致力于光网络组网系统的开发、制造和部. 署。自1999 年以来,ECI 已经在EMEA、APAC、NA 和CALA 地区为ILEC、CLEC、移动。。。

    scala-2.11.11.tgz

    cala 是一门多范式(multi-paradigm)的编程语言,设计初衷是要集成面向对象编程和函数式编程的各种特性。 Scala 运行在Java虚拟机上,并兼容现有的Java程序。 Scala 源代码被编译成Java字节码,所以它可以运行于JVM...

    chara-ani AKB48 Select Helper-crx插件

    您输入的号码可以注销网站或结束Chrome,因此您可以记录例如每个部分中已选为的项目数。您还可以看到选项屏幕上的记录。[如何使用] - 当安装此脚本时,将似乎在剧院板申请表中选择一个计划团队。如果选择计划和团队...

Global site tag (gtag.js) - Google Analytics