Scala学习笔记——implicit隐式

隐式参数

 简单隐式参数实现如下:implicit隐式传入参数

  def calcTa2(a: Int)(implicit b: Int): Float = a*b
  implicit val t = 3
  println(calcTa2(10))
隐式转换函数

对double值进行隐式转换

object ImplicitTest extends App {
  implicit def double2int(d: Double) = d.toInt
  val x: Int = 3.5
  println(x)
}
隐式调用函数
object ImplicitApp extends App {

  object SimpleSateSalesTax {
    implicit val rate: Float = 0.5F
  }

  def calcTax(amount: Float)(implicit rate: Float): Float = amount * rate
  case class ComplicatedSalesTaxData(baseRate: Float, isTaxHoliday:Boolean, storeId:Int)

  object ComplicatedSalesTax {
    private def extraTaxRateForStore(id :Int) : Float = {
      val d = id match {
        case 1 => 0.2F
        case 2 => 0.8F
      }
      d
    }

    implicit def rate(implicit cstd: ComplicatedSalesTaxData) : Float =
      if(cstd.isTaxHoliday) 0.0f
      else cstd.baseRate + extraTaxRateForStore(cstd.storeId)
  }

  {
    import SimpleSateSalesTax.rate
    val amount = 100F
    println(s"Tax on $amount = ${calcTax(amount)}")
  }

  {
    import ComplicatedSalesTax.rate
    implicit val myStore = ComplicatedSalesTaxData(0.06F, false, 2)
    val amount = 100F
    println(s"Tax on $amount = ${calcTax(amount)}")
  }


  /**
    * 简单隐式参数
    * @param a
    * @param b
    * @return
    */

  def calcTa2(a: Int)(implicit b: Int): Float = a*b
  implicit val t = 3
  println(calcTa2(10))
}
隐式转换的时机:
  1. 当方法中的参数的类型与目标类型不一致时
  2. 当对象调用类中不存在的方法或成员时,编译器会自动将对象进行隐式转换
隐式解析机制

 即编译器是如何查找到缺失信息的,解析具有以下两种规则:

  1. 首先会在当前代码作用域下查找隐式实体(隐式方法 隐式类 隐式对象)
  2. 如果第一条规则查找隐式实体失败,会继续在隐式参数的类型的作用域里查找
    类型的作用域是指与该类型相关联的全部伴生模块,一个隐式实体的类型T它的查找范围如下:
    •  如果T被定义为T with A with B with C,那么A,B,C都是T的部分,在T的隐式解析过程中,它们的伴生对象都会被搜索;
    •  如果T是参数化类型,那么类型参数和与类型参数相关联的部分都算作T的部分,比如List[String]的隐式搜索会搜索List的;
      伴生对象和String的伴生对象;
    •  如果T是一个单例类型p.T,即T是属于某个p对象内,那么这个p对象也会被搜索;
    •  如果T是个类型注入S#T,那么S和T都会被搜索;
隐式参数所遵循的规则
  • 只有最后一个参数列表中允许出现隐式参数,这也适用用于只有一个参数列表的情况。
  • implicit关键字必须出现在参数列表的最左边,而且只能出现一次。列表中出现在implicit关键字之后的参数都不是“非隐式”的。
  • 假如参数列表以implicit关键字开头,那么所有的参数都是隐式的。
“<:” 和 “>:” 和 “”作用及用法
object BorderApp extends App {

  def test[T](i: T)(implicit ev: T <:< java.io.Serializable) {
    println("OK")
  }

  test("22")
}
隐式与类型推导 <:与<:<的差异
scala> def foo[A, B <: A](a: A, b: B) = (a,b)
foo: [A, B <: A](a: A, b: B)(A, B)

scala>  foo(1, List(1,2,3))
res0: (Any, List[Int]) = (1,List(1, 2, 3))

 传入第一个参数是Int类型,第二个参数是List[Int],显然这不符合B <: A 的约束,编译器在做类型推导的时候,为了满足这个约束,会继续向上寻找父类型来匹配是否满足,于是在第一个参数被推导为Any类型的情况下,List[Int] 符合Any的子类型。

scala> def bar[A,B](a: A, b: B)(implicit ev: B <:< A) = (a,b)
bar: [A, B](a: A, b: B)(implicit ev: B <:< A)(A, B)

scala> bar(1,List(1,2,3))
<console>:13: error: Cannot prove that List[Int] <:< Int.
       bar(1,List(1,2,3))
          ^

通过隐式参数ev来证明类型时,类型推断过程不会像上面那样再向上寻找可能满足的情况,而直接报错。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值