zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    20145229&20145316 《信息安全系统设计基础》 实验二 固件设计
    20145207 《Java 程序设计》实验三 (敏捷开发与XP实践)实验报告
    《Java 程序设计》课堂实践项目-mini dc
    20145207 《Java程序设计》第10周学习总结
    《Java 程序设计》课堂实践项目-命令行参数
    20145207 实验二《Java面向对象程序设计》实验报告
    20145207《Java程序设计》第9周学习总结
    20145207信息搜集与漏洞扫描
    20145207《Java程序设计》实验二(Java面向对象程序设计)实验报告
    20145207李祉昂《网络对抗技术》可选实验 shellcode注入与Return-to-libc攻击实验
  • 原文地址:https://www.cnblogs.com/gnivor/p/4191982.html
Copyright © 2011-2022 走看看