请选择 进入手机版 | 继续访问电脑版

好程序员-千锋教育旗下高端IT职业教育品牌

400-811-9990
我的账户
好程序员

专注高端IT职业培训

亲爱的猿猿,欢迎!

已有账号,请

如尚未注册?

[BigData] 好程序员大数据教程分享Scala系列之隐式转换和隐式参数

[复制链接]
叶子老师 发表于 2019-10-15 15:08:28 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题
好程序员大数据教程Scala系列之隐式转换和隐式参数5.1. 概念
隐式转换和隐式参数是Scala中两个非常强大的功能,利用隐式转换和隐式参数,你可以提供优雅的类库,对类库的使用者隐匿掉那些枯燥乏味的细节。
5.2. 作用
隐式的对类的方法进行增强,丰富现有类库的功能
object ImplicitDemo extends App{
  //定义隐式类,可以把File转换成定义的隐式类RichFile
  implicit class RichFile(from:File){
    def read:String = Source.fromFile(from.getPath).mkString
  }
  //使用隐式类做已有类的动能的扩展
  val contents = new File("src/test1.txt").read
  println(contents)

}
5.5. 隐式类
创建隐式类时,只需要在对应的类前加上implicit关键字。比如:
object Helpers {
  implicit class IntWithTimes(x: Int) {
    def times[A](f: => A): Unit = {
      def loop(current: Int): Unit =
        if(current > 0) {
          f
          loop(current - 1)
        }
      loop(x)
    }
  }
}
这个例子创建了一个名为IntWithTimes的隐式类。这个类包含一个int值和一个名为times的方法。要使用这个类,只需将其导入作用域内并调用times方法。比如:
scala> import Helpers._
import Helpers._
scala> 5 times println("HI")
HI
HI
HI
HI
HI
使用隐式类时,类名必须在当前作用域内可见且无歧义,这一要求与隐式值等其他隐式类型转换方式类似。
只能在别的trait/类/对象内部定义。
    object Helpers {
       implicit class RichInt(x: Int) // 正确!
    }
    implicit class RichDouble(x: Double) // 错误!
构造函数只能携带一个非隐式参数。
implicit class RichDate(date: java.util.Date) // 正确!
implicit class Indexer[T](collecton: Seq[T], index: Int) // 错误!
implicit class Indexer[T](collecton: Seq[T])(implicit index: Index) // 正确!
虽然我们可以创建带有多个非隐式参数的隐式类,但这些类无法用于隐式转换。
在同一作用域内,不能有任何方法、成员或对象与隐式类同名。
object Bar
implicit class Bar(x: Int) // 错误!

val x = 5
implicit class x(y: Int) // 错误!

implicit case class Baz(x: Int) // 错误!
5.6. 隐式转换函数
是指那种以implicit关键字声明的带有单个参数的函数,这种函数将被自动引用,将值从一种类型转换成另一种类型。
使用隐含转换将变量转换成预期的类型是编译器最先使用 implicit 的地方。这个规则非常简单,当编译器看到类型X而却需要类型Y,它就在当前作用域查找是否定义了从类型X到类型Y的隐式定义。
比如,通常情况下,双精度实数不能直接当整数使用,因为会损失精度:
scala> val i:Int = 3.5
<console>:7: error: type mismatch;
found   : Double(3.5)
required: Int
       val i:Int = 3.5
                   ^
当然你可以直接调用 3.5.toInt。
这里我们定义一个从 Double 到 Int 的隐含类型转换的定义,然后再把 3.5 赋值给整数,就不会报错。
scala> implicit def doubleToInt(x:Double) = x toInt
doubleToInt: (x: Double)Int
scala> val i:Int = 3.5
i: Int = 3
此时编译器看到一个浮点数 3.5,而当前赋值语句需要一个整数,此时按照一般情况,编译器会报错,但在报错之前,编译器会搜寻是否定义了从 Double 到 Int 的隐含类型转换,本例,它找到了一个 doubleToInt。 因此编译器将把
val i:Int = 3.5
转换成
val i:Int = doubleToInt(3.5)
这就是一个隐含转换的例子,但是从浮点数自动转换成整数并不是一个好的例子,因为会损失精度。 Scala 在需要时会自动把整数转换成双精度实数,这是因为在 Scala.Predef 对象中定义了一个
implicit def int2double(x:Int) :Double = x.toDouble
Scala.Predef 是自动引入到当前作用域的,因此编译器在需要时会自动把整数转换成 Double 类型。
5.7. 隐式参数
object Test{
    trait Adder[T] {
      def add(x:T,y:T):T
    }

    implicit val a = new Adder[Int] {
      override def add(x: Int, y: Int): Int = x+y
    }

    def addTest(x:Int,y:Int)(implicit adder: Adder[Int]) = {
      adder.add(x,y)
    }

   addTest(1,2)      // 正确, = 3
   addTest(1,2)(a)   // 正确, = 3
   addTest(1,2)(new Adder[Int] {
      override def add(x: Int, y: Int): Int = x-y
    })   // 同样正确, = -1
}
好程序员大数据教程http://www.goodprogrammer.org/bigdata.shtml

精彩内容,一键分享给更多人!
回复

使用道具 举报

您需要登录后才可以回帖

本版积分规则

关注我们
好程序员
千锋好程序员

北京校区(总部):北京市海淀区宝盛北里西区28号中关村智诚科创大厦

深圳西部硅谷校区:深圳市宝安区宝安大道5010号深圳西部硅谷B座A区605-619

杭州龙驰智慧谷校区:浙江省杭州市下沙经济技术开发区元成路199号龙驰智慧谷B座7层

郑州校区:郑州市二七区航海中路60号海为科技园C区10层、12层

Copyright 2007-2019 北京千锋互联科技有限公司 .All Right

京ICP备12003911号-5 京公安网11010802011455号

请您保持通讯畅通1对1咨询马上开启