zoukankan      html  css  js  c++  java
  • scala高级内容(二)

    一. Implicit关键字

    1. 隐士转换
      (1)隐士转换函数:用implicit修饰的,只有一个参数的函数。他会被自动执行,来把一个值转换成另一个

        class RichFile(val f:File){
          def read = Source.fromFile(f).mkString
        }
        implicit def file2richFile(f:File) = new RichFile(f)   //隐士转换函数
        val result: String = new File("/home/lj/chrome.sh").read
        println(result)
      

    (2)隐士转换函数可以卸载伴生对象中,需要的时候import进来
    (3)当一个隐士函数没有被scala调用,可以显示的调用函数,有可能出现错误提示
    【注】:

        (a) 隐士转换优先转换参数,后去尝试转换调用方法的对象
        (b) 隐士转换不能同时使用多个转换。eg:convert1(convert2(a))
        (c) 二义性错误:如果2个隐士转换函数都能用到参数转换,则编译器报错
    
    1. 函数的隐士参数
      (1)函数参数列表中的某个参数,用implicit生命,则这个函数成为包含隐士参数的函数。
      (2)调用隐士参数的函数,可以显式传入参数,也可以省略不传,scala从上下文查找隐士对象,自动传进函数中

        class Delimeters(val left:String,val right:String){}
        def quote(value:String)(implicit delimeters: Delimeters)=println(delimeters.left+value+delimeters.right)
        quote("spark")(new Delimeters("<",">"))     //显示调用
        implicit val deli = new Delimeters("<<",">>")
        quote("hadoop")       // 自动推断
      
    2. 隐士转换function作为函数的隐士参数
      有时一个函数的参数类型为泛型T,不能确定参数有哪些方法可被调用。因此,函数的参数类表中,使用隐士转换函数作为参数,从而确定参数列表有哪些方法能被调用

        //Predef中含有大量的T->Ordered[T]的隐士转换函数
        def getBigger[T](a:T,b:T)(implicit ord : T=>Ordered[T])={  //ord是一个隐士转换函数,用implicit修饰后,成为隐士参数。scala要根据前文查找是否有这样一个函数
          if(a>b) a else b
        }
        println(getBigger(2,3))
      
    3. 上下文界定
      上下文界定是对隐士参数的简化语法,这个隐士参数的类型要是M[T],简化掉函数参数中的隐士参数。那函数内部如何使用原来的隐士参数呢,2种方法:定义内部函数,把省略的隐士参数在内部函数中还原出来;第二个是用implicity还原这个变量

      object Test extends App{
        // 隐士参数
        def max[T](a:T,b:T)(implicit cp:Ordering[T])={
          if (cp.compare(a,b)>0) a else b
        }
        println(max(1,3))
      
        // 上下文界定精简隐士参数,表示的语义还是要有Ordering[T]类型的隐士参数
        def max2[T:Ordering](a:T,b:T)={
          // 1.内部函数使用隐士参数
          def innermax(implicit op:Ordering[T]) = {
            if (op.compare(a,b)>0) a else b
          }
          innermax
        }
        println(max2(3,6))
      
      
        // 2. implicify还原隐士参数
        def max3[T:Ordering](a:T,b:T)={
          val op = implicitly[Ordering[T]]
          if (op.compare(a,b)>0) a else b
        }
        println(max3(23,1))
      }
      
    4. 类型证明参数
      (1)格式:implicit 类型证明参数名:泛型1 <:<,<%<,<=< 泛型2
      (2)作用:当函数右两个泛型时,类型证明参数可以证明一个泛型是另一个泛型的(子类型,视图类型,相等类型)

        //firstlast方法,会在调用时确定2个类型。C:函数的参数类型。A是iterable里的类型(List中的元素类型)。
        def firstLast[A,C](it:C)(implicit demonstrate: C<:<Iterable[A]) = {  // 如果没有类型证明参数demonstrate,定义函数时,无法确定C是什么类型。也就无法调用参数的方法
          (it.head,it.last)
        }
        println(firstLast(List(1,2,5)))                    // scala推断出泛型[Int,List[Int]]
        println(firstLast[Int,List[Int]](List(1,2,5)))     // 手动指定泛型[Int,List[Int]]
      

    二. @implicitNotFound注解

    1. @implicitNotFound
      @implicitNotFound注解在无法找到隐士参数,隐士转换,或推出的泛型不匹配时给出提示信息

        @implicitNotFound(msg = "Cannot prove that ${From} <:< ${To}.")
        sealed abstract class <:<[-From, +To] extends (From => To) with Serializable
      
    2. Manifest和typetag

      // Manifest和typetag存储被擦出泛型信息
      class Foo{class Bar}
      def m(f: Foo)(b: f.Bar)(implicit ev: TypeTag[f.Bar]) = ev   // TypeTag解决Manifest的依赖路径问题
      val f1 = new Foo;val b1 = new f1.Bar
      val f2 = new Foo;val b2 = new f2.Bar
      val ev1 = m(f1)(b1)
      val ev2 = m(f2)(b2)
      println(ev1==ev2)    // false。 使用manifest的结果是true
    
  • 相关阅读:
    C语言I博客作业05 sun
    C语言I博客作业08 sun
    C语言I博客作业02 sun
    C语言I博客作业04 sun
    elastix的web端口修改
    mysql.proc错误解决
    Client.Error.MessageSend 错误解决方案
    让secureCRT正确显示中文
    elastix的多个inbound route的设置
    PHP5.1时间相差8小时问题解决。
  • 原文地址:https://www.cnblogs.com/72808ljup/p/5532299.html
Copyright © 2011-2022 走看看