部分文章内容为公开资料查询整理,原文出处可能未标注,如有侵权,请联系我,谢谢。邮箱地址:gnivor@163.com ►►►需要气球么?请点击我吧!

Scala学习笔记--隐式转换


隐式转换的规则:
1.无歧义规则:隐式转换唯有不存在其他可插入转换的前提下才能插入
   若编译器有两种方法修正x+y 如convert1(x)+y,convert2(x)+y,会报错
2.单一调用规则:只尝试一个隐式操作,编译器不会把x+y重写成convert1(convert2(x))+y
3.显式调用规则:若编写的代码没有错误,则不会尝试任何隐式操作
4.命名隐式转换:隐式转换可以任意命名

def main(args:Array[String]):Unit={
    implicit def doubleToInt(x:Double)  = x.toInt    
    val i:Int = 3.5;
    println(i)    
    
    //编译器在语境中看到了Double,但它需要的是Int。
    //如果没有第一行 implicit def doubleToInt(x:Double)  = x.toInt 编译器会报错
    //###但是在放弃之前,它搜索了从Double 到Int的隐式转换。
    //在本例中,它发现了一个doubleToInt,编译器于是自动插入了doubleToInt调用
    //代码实际变成了val i:Int = doubleToInt(3.5)
  }

 

 

隐式参数

 

class PreferredPrompt(val preference:String)
class PreferredDrink(val preference:String)
object Greeter{
  def greet(name: String)(implicit prompt:PreferredPrompt,drink:PreferredDrink){ //参数列表被标记为implicit,也就是说它可以被隐式提供
    println("Welcome," + name + ". The system is ready.");
    println("喝点什么?")
    println(drink.preference );
    println(prompt.preference);
    
  }
}

object Test3{
  def main(args:Array[String]):Unit={
    
    //为了让编译器隐式提供参数,必须先定义期望类型的变量
    implicit val p1 = new PreferredPrompt("Lin>")
    implicit val p2 = new PreferredDrink("tea")
    //p1本身也被标记为implicit 否则不能用来补充下面确实的参数列表
    Greeter.greet("JJ")
  }
  /*//不使用隐式参数的情况
  def main(args:Array[String]):Unit={
    val p1 = new PreferredPrompt("Lin")    
    Greeter.greet("JJ")(p1)
  }
  */
}

 结果:

Welcome,JJ. The system is ready.
喝点什么?
tea
Lin>

 

隐式转换

隐式的函数参数也可以被用作隐式转换。为了明白它的重要性,首先考虑如下泛型函数:

def smaller[T](a:T,b:T)={
  if(a<b) a else b 
}

这实际上行不通,因为它并不知道a和b数以一个带有<操作符的类型。

我们可以提供一个转换函数来达到目的:

def smaller[T](a:T,b:T)(implicit order: T=>Ordered(T))={
  if(order(a)<b) a else b 
}

由于Ordered[T]特质有一个接受T作为参数的<操作符,因此这个版本是正确的。

注意order是一个带有单个参数的函数,被打上了implicit标签,并且有一个以单个标识符出现的名称。

因此,它不仅是隐式参数,而且是隐式转换。因此,在函数体中可以略去对order的显示调用

def smaller[T](a:T,b:T)(implicit order: T=>ordered(T))={
  if(a<b) a else b 
}

 

另一个例子。

object Test4{
  def main(args:Array[String]):Unit={
    val l1 = List(24,6,7,34,5,14,23)
    println(maxListUpBound(l1))
  }
  def maxListUpBound[T](elements:List[T])(implicit orderer:T=>Ordered[T]):T={//这里用到了隐式转换   
//  def maxListPoorStyle[T](elements:List[T])(implicit orderer:(T,T)=>Boolean):T={  //太过平凡
//  def maxListUpBound[T<:Ordered[T]](elements:List[T]):T={  //不可行,因为T未必是Ordered[T]的子类
//  def maxListUpBound(elements:List[Int]):Int={
    elements match{
      case List()=> throw new IllegalArgumentException("empty list!")
      case List(x)=>x
      case x::rest =>
        val maxRest = maxListUpBound(rest)(orderer)
        if(orderer(x) > maxRest) x; 
        else maxRest
    }
  }
}


/*隐式参数的样式规则。最好对隐式参数的类型使用自定义命名的类型,例如不用String 而用
  PreferredPrompt 和PreferredDrink
 反例
def maxListPoorStyle[T](elements:List[T])(implicit orderer:(T,T)=>Boolean):T
为了使用函数的这个版本,调用这必须提供类型为(T,T)=>Boolean的orderer参数
这种类型过于平凡,包含了任何两个T对象产生的Boolean函数
 */

 

视界

def maxListUpBound[T<%Ordered[T]](elements:List[T]):T={
  elements match{
      case List()=> throw new IllegalArgumentException("empty list!")
      case List(x)=>x
      case x::rest =>
        val maxRest = maxListUpBound(rest)
        if(x > maxRest) x; 
        else maxRest
    }
 
}
可以认为 T<%Ordered[T] 是在说, 任何的T都好,只要能把T当做Orderer[T]即可
例如 尽管Int不是Ordered[Int]的子类型,但是只要Int到Ordered[Int]的隐式转换可用
仍然可以把List[T]传给maxListUpBound

 

posted @ 2014-12-29 16:38  流了个火  阅读(345)  评论(0编辑  收藏  举报
►►►需要气球么?请点击我吧!►►►
View My Stats