Scala之隐式转换

1.什么是隐式转换

我们经常引入第三方库,但当我们想要扩展新功能的时候通常是很不方便的,因为我们不能直接修改其代码。scala提供了隐式转换机制和隐式参数帮我们解决诸如这样的问题。

Scala中的隐式转换是一种非常强大的代码查找机制。当函数、构造器调用缺少参数或者某一实例调用了其他类型的方法导致编译不通过时,编译器会尝试搜索一些特定的区域,尝试使编译通过。

2.常用方法:

转换类型为期望的类型

转换类型为期望的类型

当我们尝试把一个带有精度的数字复制给Int类型时,编译器会给出编译错误,因为类型不匹配。当我们创建了一个double to int的隐式转换之后编译正常通过。
还有一种情况是与新类型的操作:

 case class Rational(n: Int, d: Int) {
    def +(r: Rational) = Rational(n + r.n, d + r.d)
  }
implicit def int2Rational(v: Int) = Rational(v, 1)
 Rational(1, 1) + Rational(1, 1)//可行
 1 + Rational(1, 1)//可行,隐式转换,调用int2Rational

隐式类

目前,一般不推荐 implicit def 的方式,而推荐用隐式类的方法,如下:

implicit class Calc(x:Int){
    def add(a:Int):Int = a +x
}
println(1.add(2))//1自动实例化为Calc的类型

隐式视图

隐式视图:把一种类型转换为其他的类型,转换后的新类型称为视图类型。隐式视图会用于以下两种场景:
当传递给函数的参数与函数声明的类型不匹配时
隐式视图

当调用foo.bar,且foo中并没有bar函数(或成员)时(常用于丰富已有的类库):

  class Strings(str: String) {
    def compress = str.filter(_ != ' ').mkString("")
  }
  implicit def strings(str: String): Strings = new Strings(str)

  " a b c d ".compress//本身String格式没有compress函数,但是此处可用饮食转换将String转为自己造的Strings

另外还有类型类和模拟新语法等功能可见Scala隐式转换

另:隐式操作规则

  • 标记规则:只有标记为implicit的变量,函数或对象定义才能被编译器当做隐式操作目标。
  • 作用域规则:插入的隐式转换必须是单一标示符的形式处于作用域中,或与源/目标类型关联在一起。

单一标示符是说当隐式转换作用时应该是这样的形式:file2Array(arg).map(fn)的形式,而不是foo.file2Array(arg).map的形式。

假设file2Array函数定义在foo对象中,我们应该通过import foo._或者import foo.file2Array把隐式转换导入。简单来说,隐式代码应该可以被”直接”使用,不能再依赖类路径。

假如我们把隐式转换定义在源类型或者目标类型的伴生对象内,则我们可以跳过单一标示符的规则。因为编译器在编译期间会自动搜索源类型和目标类型的伴生对象,以尝试找到合适的隐式转换。

  • 无歧义规则:不能存在多于一个隐式转换使某段代码编译通过。因为这种情况下会产生迷惑,编译器不能确定到底使用哪个隐式转换。
Scala转换是一种强大的语言特性,可让编译器在编译期间自动推导信息,从而减少代码量,让程序员省去复杂重复的代码,忽略冗长、过于细节的部分[^1]。以下为几种常见的Scala转换及使用方法: ### 函数 函数使用`implicit`关键字定义,编译器会在需要时自动调用,从而将一种类型转换为另一种类型。 ```scala // 定义函数 implicit def intToDouble(x: Int): Double = x.toDouble // 使用转换 val num: Double = 5 ``` ### 参数 在函数或方法中定义用`implicit`修饰的参数,Scala会尝试找到指定类型且用`implicit`修饰的对象(即值)并注入参数。查找位置为当前作用域内可见的`val`或`var`定义的变量,以及参数类型的伴生对象内的值。 ```scala object ImplicitOps3 { def main(args: Array[String]): Unit = { var myArray: Array[Int] = Array(5, 6, 45, 1, 8, 9, 25, 0, 4, 91) println("排序前:" + myArray.mkString("[", ",", "]")) var newArray = myArray.sortWith(_ < _) println("排序后:" + newArray.mkString("[", ",", "]")) implicit val ord = new Ordering[Int]() { override def compare(x: Int, y: Int): Int = y.compareTo(x) } newArray = myArray.sorted println("排序后:" + newArray.mkString("[", ",", "]")) } } ``` ### Scala 2.10 之后引入了类,使用`implicit`声明类可扩展类的功能。类所带的构造参数有且只能有一个,且必须被定义在“类”或“伴生对象”或“包对象”里。 ```scala object TestImplicitClass { implicit class MyRichInt(val self: Int) { def myMax(num: Int): Int = if (num > self) num else self def myMin(num: Int): Int = if (num > self) self else num } def main(args: Array[String]): Unit = { println(12.myMax(15)) println(12.myMin(15)) } } ``` ### 解析机制 首先会在当前代码作用域下查找实体(方法、类、对象),若查找失败,会继续在参数的类型的作用域里查找,类型的作用域指与该类型相关联的全部伴生对象以及该类型所在包的包对象[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值