Scala之隐式转换implicit详解

假设我们有一个表示文本的行数的类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

让我们看看在编译时加入 “-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就会变为一个整型。

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

时间: 2024-10-12 16:13:22

Scala之隐式转换implicit详解的相关文章

scala自定义隐式转换

Scala自定义隐式转换 一.编写隐式转换类 /** * Author Mr. Guo * Create 2019/4/20 - 17:40 */ object StringImprovments { implicit class StringImprove(s: String) { def increment = s.toString.map(c => (c + 1).toChar) } implicit class Intc(i: Int) { def xx = { Integer.pars

Scala 中的隐式转换 implicit

Scala语言中的隐式转换是一个十分强大的语言特性,主要可以起到两个作用: 一.自动进行某些数据类型的隐式转换 String类型是不能自动转换为Int类型的,所以当给一个Int类型的变量或常量赋予String类型的值时编译器将报错.所以,一下语句是错误的. val x: Int = "100" 如果需要将一个字符串类型的整形数值赋给Int,比如使用String.toInt方法,例如: v al x: Int = "100".toInt 如果想让字符串自动转换为整形,

转载:深入理解Scala的隐式转换系统

摘要: 通过隐式转换,程序员可以在编写Scala程序时故意漏掉一些信息,让编译器去尝试在编译期间自动推导出这些信息来,这种特性可以极大的减少代码量,忽略那些冗长,过于细节的代码. 使用方式: 1.将方法或变量标记为implicit 2.将方法的参数列表标记为implicit 3.将类标记为implicit Scala支持两种形式的隐式转换: 隐式值:用于给方法提供参数 隐式视图:用于类型间转换或使针对某类型的方法能调用成功 隐式值: 例1:声明person方法.其参数为name,类型String

深入理解Scala的隐式转换系统

摘要: 通过隐式转换,程序员可以在编写Scala程序时故意漏掉一些信息,让编译器去尝试在编译期间自动推导出这些信息来,这种特性可以极大的减少代码量,忽略那些冗长,过于细节的代码. 使用方式: 1.将方法或变量标记为implicit 2.将方法的参数列表标记为implicit 3.将类标记为implicit Scala支持两种形式的隐式转换: 隐式值:用于给方法提供参数 隐式视图:用于类型间转换或使针对某类型的方法能调用成功 隐式解析机制 即编译器是如何查找到缺失信息的,解析具有以下两种规则: 1

IDEA的auto import 与 Scala的隐式转换

设置IDEA的auto import 之后,编写Spark应用程序时的一些自动导入情况及其说明. 1.普通类的自动导入 var cnames = new ArrayBuffer[String]() var ips = new ArrayBuffer[String]() 直接根据提示alt+enter便可以导入ArrayBuffer类包 2.需要隐式转换 val joinRDD = reqRDD.join(respRDD).map(x => (x._2._1, x._2._2)).reduceBy

Scala特性: 隐式转换

1.隐式转换特征: 1)隐式参数的用法 · 获取可能的预期类型 · 获取预期类型,并且拥有预期类型的行为 · 对信息进行补充说明(一般用函数做隐式参数的比较多) 2)隐式类: 3)隐式method:

Scala中的Implicit(隐式转换,隐式参数,隐式类)

文章来自:http://www.cnblogs.com/hark0623/p/4196452.html  转发请注明 代码如下: /** * 隐式转换 隐式参数 隐式类 */ //隐式转换 class Implicit(a: A) { def Test: Unit = { println("Implicit") } } class A { } object Implicit { //隐式转换 implicit def a2Implicit(a: A) = new Implicit(a)

scala学习笔记-隐式转换与隐式参数(18)

Scala提供的隐式转换和隐式参数功能,是非常有特色的功能.是Java等编程语言所没有的功能.它可以允许你手动指定,将某种类型的对象转换成其他类型的对象.通过这些功能,可以实现非常强大,而且特殊的功能. Scala的隐式转换,其实最核心的就是定义隐式转换函数,即implicit conversion function.定义的隐式转换函数,只要在编写的程序内引入,就会被Scala自动使用.Scala会根据隐式转换函数的签名,在程序中使用到隐式转换函数接收的参数类型定义的对象时,会自动将其传入隐式转

Scala隐式转换类遇到的问题

今天练习Scala的隐式转换类遇到的一个问题,测试代码如下: object ImplcitTest { def main(args: Array[String]) { import Context._ val person1 = User("zhangsan") println(person1.getStr()) val filePath = Thread.currentThread.getContextClassLoader.getResource("test.txt&qu