zoukankan      html  css  js  c++  java
  • Scala 隐式转换 隐式转换参数 隐式类 隐式对象

    
    

    隐式转换

    • 我们需要某个类中的一个方法,但是这个类没有提供这样的一个方法,所以我们需要隐式转换,转换成提供了这个方法的类,然后再调用这个方法在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 Implicit_Conversions {
        def main(args: Array[String]): Unit = {
            //导入隐式转换
            import Context.file2RichFile
            //File类本身没有read方法 通过隐式转换完成
            //这里的read方法是RichFile类中的方法  需要通过隐式转换File --> RichFile
            println(new File("E:\2.txt").read)
          
        }
    }

     隐式转换参数

     隐式转换参数,也就是一个函数参数被implicit关键字修饰,把这些参数称为隐式转换参数

    隐式转换参数不一定需要赋值,因为有默认值(该参数会自动在其作用域范围类检索 包含implicit 关键字的 并且相适应的变量,来进行赋值)
    object ImplicitArrayOps {
    
      //隐式转换参数,也就是一个函数参数被implicit关键字修饰,把这些参数称为隐式转换参数
      //隐式转换参数不一定需要赋值,因为有默认值(该参数会自动在其作用域范围类检索 包含implicit 关键字的 并且相适应的变量,来进行赋值 )
      def main(args: Array[String]): Unit = {
        val array = Array(3, 5, 6, 1, 2, 4, 3, 10)
        println("排序前的数组;" + array.mkString("[",", ", "]"))
        //传统排序
        println("==========传统排序(升序)==============")
        println("传统(升序)排序后的数组;" + array.sortWith(_ < _).mkString("[",", ", "]"))
    
        println("==========传统排序(默认简写)==============")
        // //  def sorted[B >: A](implicit ord : scala.math.Ordering[B]) : Repr = { /* compiled code */ }
        println("传统(默认升序)排序后的数组;" + array.sorted.mkString("[",", ", "]"))
    
        implicit  var ord = new Ordering[Int] (){
          override def compare(x: Int, y: Int) = y.compareTo(x)  //降序排序
        }
    
        println("==========传统排序(隐式转换)==============")
        //  def sorted[B >: A](implicit ord : scala.math.Ordering[B]) : Repr = { /* compiled code */ }
        println("传统(默认降序)排序后的数组;" + array.sorted.mkString("[",", ", "]"))
    
      }
    
    }

     

     

    object ImplicitOps {
    
      def main(args: Array[String]): Unit = {
    
        implicit var studReport = new StudentSubmitReport("home")
    //    implicit var studReport2 = new StudentSubmitReport("company")
        SignForReport("KPWONG")(new StudentSubmitReport("beijing"))
        SignForReport("KPWONG")
      }
    
      def SignForReport(name:String)(implicit stuReprot:StudentSubmitReport) {
        stuReprot.WriteReport(name + " come to " + stuReprot.location )
      }
    
    }
    class StudentSubmitReport {
      var location :String = _
      def this(location:String){
        this()
        this.location = location
      }
       def WriteReport(content: String) ={
          println(content)
       }
    }

     隐式类

    在scala2.10后提供了隐式类,可以使用implicit声明类,但是需要注意以下几点:

    • 其所带的构造参数有且只能有一个
    • 隐式类必须被定义在类,伴生对象和包对象里
    • 隐式类不能是case class(case class在定义会自动生成伴生对象与2矛盾
    • 作用域内不能有与之相同名称的标示符
    • 有时候进行代码重构,要增强他的某项功能同时又不想做太大的改动
    • 更多用的是隐式转换,隐式类用的不多
    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)
        }
    }
    隐式解析机制
    即编译器是如何查找到缺失信息的,解析具有以下两种规则:
    1.首先会在当前代码作用域下查找隐式实体(隐式方法  隐式类 隐式对象)
     
    2.如果第一条规则查找隐式实体失败,会继续在隐式参数的类型的作用域里查找
    类型的作用域是指与该类型相关联的全部伴生模块,一个隐式实体的类型T它的查找范围如下:
        (1)如果T被定义为T with A with B with C,那么A,B,C都是T的部分,在T的隐式解析过程中,它们的伴生对象都会被搜索
        (2)如果T是参数化类型,那么类型参数和与类型参数相关联的部分都算作T的部分,比如List[String]的隐式搜索会搜索List的
    伴生对象和String的伴生对象
        (3) 如果T是一个单例类型p.T,即T是属于某个p对象内,那么这个p对象也会被搜索
        (4) 如果T是个类型注入S#T,那么S和T都会被搜索
     
    隐式转换的前提:
    1.不存在二义性(如例1)
     
    2.隐式操作不能嵌套使用(如 convert1(covert2(x)))+y
     
    3.代码能够在不使用隐式转换的前提下能编译通过,就不会进行隐式黑铁
  • 相关阅读:
    【k8s部署】6. 部署 worker 节点
    【k8s部署】5. 部署 master 节点
    【k8s部署】4. 部署 etcd 集群
    【k8s部署】3. 安装和配置 kubectl
    【k8s部署】2. 创建CA根证书和秘钥
    【k8s部署】1. 环境准备和初始化
    【踩坑】OpenStack4j使用过程中关于OSClientSession被更改的问题记录
    10. 配置Horizon — OpenStack Queens 三节点部署
    9. 配置网络(VXLAN_OpenvSwitch)— OpenStack Queens 三节点部署
    Mac安装svn(解决新系统Xcode不支持问题)
  • 原文地址:https://www.cnblogs.com/kpwong/p/14154831.html
Copyright © 2011-2022 走看看