Scala 隐式转换

作者: 他与理想国 | 来源:发表于2018-08-22 22:05 被阅读0次

    隐式转换

    • 我们需要某个类中的一个方法,但是这个类没有提供这样的一个方法,所以我们需要隐式转换,转换成提供了这个方法的类,然后再调用这个方法
      • 第一步,需要一个增强的类,里面提供我们想要的方法,接收的参数的类型一定要是被增强类的类型。
      • 第二部,还需要在单例对象中写明隐式转换
      • 第三步,把隐式转换函数导进来
    • 在spark中隐士转换都写在伴生对象中,因为类的实例肯定能找到伴生对象的,在一个作用域当中
     
    import scala.io.Source
    import java.io.File
     
    
    //这里的RichFile相当于File的增强类 需要将被增强的类作为参数传入构造器中
    class RichFile(val file: File) {
      def read = {
          Source.fromFile(file.getPath).mkString
      }
    }
     
    //implicit是隐式转换的关键字 这里定义一个隐式转换函数把当前类型转换成增强的类型
    object Context {
        //File --> RichFile
        implicit def file2RichFile(file: File) = new RichFile(file)
    }
     
    object Hello_Implicit_Conversions {
        def main(args: Array[String]): Unit = {
            //导入隐式转换
            import Context.file2RichFile
            //File类本身没有read方法 通过隐式转换完成
            //这里的read方法是RichFile类中的方法  需要通过隐式转换File --> RichFile
            println(new File("E:\\projectTest\\1.txt").read)
          
        }
    }
    
    

    隐式参数

    
    object Context_Implicits {
        implicit val default: String = "Java"
    }
    
    object Param {
        //函数中用implicit关键字 定义隐式参数
        def print(context: String)(implicit language: String){
            println(language+":"+context)
        }
    }
    
    object Implicit_Parameters {
        def main(args: Array[String]): Unit = {
            //隐式参数正常是可以传值的,和普通函数传值一样  但是也可以不传值,因为有缺省值(默认配置)
            Param.print("Spark")("Scala")   //Scala:Spark
            
            import Context_Implicits._
            //隐式参数没有传值,编译器会在全局范围内搜索 有没有implicit String类型的隐式值 并传入
            Param.print("Hadoop")          //Java:Hadoop
        }
    }
    
    

    隐式参数与隐式转换

    
    object Implicit_Conversions_with_Implicit_Parameters {
      
        def main(args: Array[String]): Unit = {
            
            /**
             * (1)bigger[T]为泛型函数
             * (2)bigger(...)(...)该函数是柯里化的
             * (3)第二个括号传入的是一个匿名函数,类型为T => Ordered[T] orders是隐式参数 输入类型为T类型, 返回类型为Ordered[T]类型
             * 
             * */
            def bigger[T](a: T, b: T)(implicit ordered: T => Ordered[T]) = {
                /**
                 * ordered(a) > b中的">"是一个函数 具体定义在Ordered类中 
                 * Source define:
                 *        def >  (that: A): Boolean = (this compare that) >  0
                 */
                if (ordered(a) > b) a else b   // if (a > b) a else b  这样写也可以
            }
          
            println(bigger(4, 3))                 //4
            println(bigger("Spark", "Hadoop"))    //Spark
            
        }
    }
    
    

    上下文界定中的隐式参数

    • 在每次上下文运行的实例对象中将具体的值注入到隐式参数中,而且注入的过程是自动的
    
    //[T: Ordering]:说明存在一个隐式类型Ordering[T]
    class Pair_Implicits[T: Ordering](val first: T, val second: T){
        //声明一个隐式类型对象传入函数 
        def bigger(implicit ordered: Ordering[T]) = {
            if (ordered.compare(first, second) > 0) first else second
        }
    }
    
    //简化上面的写法
    class Pair_Implicitly[T: Ordering](val first: T, val second: T){
        def bigger = 
          if (implicitly[Ordering[T]].compare(first, second) > 0) first else second
    }
    
    //进一步简化
    class Pair_Implicitly_Ordereded[T: Ordering](val first: T, val second: T) {
        def bigger = {
            import Ordered._
            if (first > second) first else second
        }
    }
    
    object Context_Bounds_Internals {
      
        def main(args: Array[String]): Unit = {
          println(new Pair_Implicits(7, 9).bigger)
          println(new Pair_Implicitly(7, 9).bigger)
          println(new Pair_Implicitly_Ordereded(7, 9).bigger)
          
        }
    }
    
    

    隐式类

    • 有时候进行代码重构,要增强他的某项功能同时又不想做太大的改动
    • 更多用的是隐式转换,隐式类用的不多
    
    import scala.io.Source
    import java.io.File
     
    
    object Context_Helper {
        implicit class FileEnhancer(file: File) {
            def read = Source.fromFile(file.getPath).mkString
        }
        implicit class Op(x: Int) {
            def add(second: Int) = x + second
        }
    }
     
    object Implicits_Class {
      
        def main(args: Array[String]): Unit = {
            import Context_Helper._
    
            /**
             * File对象中并没有read方法 编译器会在全局范围内查询匹配的隐式类
             * 在Context_Helper导入的类中有FileEnhancer 接受File类型的类 会自动匹配 、
             * 使得File对象通过这种隐式的方法具有read方法
             */
            println(new File("E:\\projectTest\\1.txt").read)   
            
            println(1.add(2))    //3
            
        }
    }
    
    

    隐式对象

    
    abstract class Template[T] {
        def add(x: T, y: T): T
    }
    abstract class SubTemplate[T] extends Template[T] {
        def unit: T
    }
    
    object Implicits_Object {
        def main(args: Array[String]): Unit = {
        
            implicit object StringAdd extends  SubTemplate[String] {
                def add(x: String, y: String): String = x concat y
                def unit: String = ""
            }  
            
            //定义隐式对象  定义方式:implicit object XXX
            implicit object IntAdd extends SubTemplate[Int] {
                def add(x: Int, y: Int): Int = x + y
                def unit: Int = 0
            } 
            
            //implicit m: SubTemplate[T]中 m是一个隐式对象就是实际在运行的对象
            def sum[T](xs: List[T])(implicit m: SubTemplate[T]): T =
                if (xs.isEmpty) m.unit 
                else m.add(xs.head, sum(xs.tail))
                
            println(sum(List(1, 2, 3)))         //6
            println(sum(List("Scala", "Spark", "Kafka")))   //ScalaSparkKafka
          
        }
    }
    
    

    通过伴生对象进行隐式转换

     
    import java.io.File
    import scala.io.Source
     
    
    class RichFile(val file: File) {
        def read = Source.fromFile(file.getPath).mkString
    }
    
    class File_Impkicits(path: String) extends File(path)
    object File_Impkicits {
        implicit def file2RichFile(file: File) = new RichFile(file) //file-->RichFile
    }
     
    object Implicits_Internals {
        def main(args: Array[String]): Unit = {
           /*
            * 这里没有导入隐式对象
            * 
            * 通过给File_Impkicits类 构建一个伴生对象 在伴生对象内部顶一个隐式转换的方法
            * 
            * 执行顺序:
            * 1.搜索File_Impkicits有无read方法 
            * 2.在上下文上搜索(有无导入的隐式对象)
            * 3.搜索File_Impkicits的伴生对象内有无隐式转换  发现implicit关键 尝试匹配类型  
            *    例如这里匹配file2RichFile(file: File) 返回类型为RichFile 在RichFile中发现read方法
            */
           println(new File_Impkicits("E:\\projectTest\\1.txt").read)
        }
    }
    
    

    相关文章

      网友评论

        本文标题:Scala 隐式转换

        本文链接:https://www.haomeiwen.com/subject/obduiftx.html