Scala Implicit Conversion

Scala Implicit Conversion函数

从一个简单例子出发,咱们定义一个函数接受一个字符串参数,并进行输出spa

def func(msg: String): Unit = println(msg)

这个函数在func("11")调用时候正常,可是在执行func(11)或func(1.1)时候就会报error: type mismatch的错误。这个问题很好解决:scala

  1. 针对特定的参数类型,重载多个func函数,这个不难,传统JAVA中的思路,可是须要定义多个函数code

  2. 使用超类型,好比使用AnyVal,Any,这样的话比较麻烦,须要在函数中针对特定的逻辑作类型转化,从而进一步处理对象

上面两个方法使用的是传统JAVA思路,虽然均可以解决该问题,可是缺点是不够简洁;在充满了语法糖的Scala中,针对类型转换提供了特有的implicit隐式转换的功能。ci

隐式转化是一个函数,能够针对一个变量在须要的时候自动的进行类型转换;针对上面的例子,咱们能够定义intToString函数字符串

def func(msg: String): Unit = println(msg)

implicit def intToString(i: Int): String = i.toString

func("hello world!")
func(123)

运行并输出,get

C:\WorkSpace6-scala\scala-train\src\com\usoft>scala implicit.scalait

warning: there was one feature warning; re-run with -feature for detailsio

one warning found

hello world!

123

此时在调用func(11)时候, scala会自动针对11进行intToString函数的调用, 从而实现能够在func函数已有的类型上提供了新的类型支持,这里有几点要说一下:

  1. 隐式转换的核心是from类型和to类型,至于函数名称并不重要;上面咱们取为intToString,只是为了直观,int2str的功能是同样的;隐式转换函数只关心from-to类型之间的匹配,好比咱们须要to类型,可是提供了from类型,那么相应的implicit函数就会调用 

  2. 隐式转换只关心类型,因此若是同时定义两个隐式转换函数,from/to类型相同,可是函数名称不一样,这个时候函数调用过程当中若是须要进行类型转换,就会报ambiguous二义性的错误,即不知道使用哪一个隐式转换函数进行转换

上面咱们看到的例子是将函数的参数从一个类型自动转换为一个类型的例子,在Scala中,除了针对函数参数类型进行转换之外,还能够对函数的调用者的类型进行转换。

好比A+B,上面咱们谈到是针对B进行类型自动转换, 其实能够在A上作类型转换,下面咱们拿一个例子来讲明

class IntWritable(_value: Int) {
  var value = _value

  def +(that: IntWritable): IntWritable = {
    new IntWritable(that.value + value)
  }
}

implicit def intToWritable(int: Int) = new IntWritable(int)
new IntWritable(10) + 10

上面咱们首先定义了一个类:IntWritable,并为int提供了一个隐式类型转换intToWritable,从而可使得IntWritable的+函数在原先只接受IntWritable类型参数的基础上,接受一个Int类型的变量进行运算,即new IntWritable(10) + 10能够正常运行

如今换一个角度将"new IntWritable(10) + 10" 换为"10 + new IntWritable(10)"会是什么结果呢?会报错误吗?

以下代码,

class IntWritable(_value: Int) {
  var value = _value

  def +(that: IntWritable): IntWritable = {
    new IntWritable(that.value + value)
  }
}

implicit def intToWritable(int: Int) = new IntWritable(int)
//implicit def writableToInt(that: IntWritable) = that.value


//val result1 = new IntWritable(10) + 10
val result2 = 10 + new IntWritable(10)

//println(result1.getClass.getName)
println(result2.getClass.getName) //Main$$anon$1$IntWritable

按道理是应该报错误,首先一个Int内置类型的+函数,没有IntWritable这个参数类型;其次,咱们没有针对 IntWritable 类型提供到 Int 的隐式转换,

即没有提供writableToInt的implicit函数。

可是结果是什么?

10 + new IntWritable(10) 是能够正常运行的,并且整个表达的类型为IntWritable,而不是Int,即Int的10被intToWritable函数隐式函数转换为IntWritable类型;

结论:隐式转换能够针对函数参数类型和函数对象进行类型转换;如今问题来了,看下面的例子

class IntWritable(_value: Int) {
  var value = _value

  def +(that: IntWritable): IntWritable = {
    new IntWritable(that.value + value)
  }
}

implicit def intToWritable(int: Int) = new IntWritable(int)
implicit def writableToInt(that: IntWritable) = that.value


val result1 = new IntWritable(10) + 10
val result2 = 10 + new IntWritable(10)

println(result1.getClass.getName) //Main$$anon$1$IntWritable
println(result2.getClass.getName) //int

在上面的IntWritable类的基础上,咱们提供了两个隐式类型转换函数,即Int和IntWritable之间的双向转换;这样的状况下result1和result2两个变量的类型是什么?

答案:result1的类型为IntWritable, result2的类型Int;很好理解, result1中的Int类型的10被intToWritable隐式转换为IntWritable;而result2中的IntWritable(10)被writableToInt 隐式转换为Int类型;

你确定会问?result2中为何不是像上面的例子同样, 把Int类型的10隐式转换为IntWritable类型呢?缘由就是隐式转换的优先级;

发生类型不匹配的函数调用时, scala会尝试进行类型隐式转换;首先优先进行函数参数的类型转换,若是能够转换, 那么就完成函数的执行; 不然尝试去对函数调用对象的类型进行转换; 若是两个尝试都失败了,就会报方法不存在或者类型不匹配的错误;

OK, Scala的隐式转换是Scala里面随处可见的语法。

================END================

相关文章
相关标签/搜索