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 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)
    }
}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,219评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,363评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,933评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,020评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,400评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,640评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,896评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,597评论 0 199
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,327评论 1 244
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,581评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,072评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,399评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,054评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,083评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,849评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,672评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,585评论 2 270

推荐阅读更多精彩内容

  • 什么是隐式转换 我们经常引入第三方库,但当我们想要扩展新功能的时候通常是很不方便的,因为我们不能直接修改其代码。s...
    福克斯记阅读 13,676评论 0 25
  • 隐式转换,你可以手动指定在找不到方法或变量时将某种类型的变量或者类转换成指定的类型,就像从地狱中召唤一个自己没有功...
    苟雨阅读 367评论 0 2
  • Implict conversion 隐式定义是编译器为了修正类型错误而添加的定义,通过在程序中添加隐式定义,自动...
    wangdy12阅读 1,637评论 0 2
  • 本文为《快学 Scala》以及《深入了解 Scala》的读书笔记 1 概述 Scala 的隐式转换系统提供了一套良...
    runzhliu阅读 459评论 0 0
  • 25岁,没房,没车,没存款,也没有女朋友,只有拖延症。 即将踏上社会,不懂人情世故,不懂江湖。 这是2016年毕业...
    Fred_young阅读 451评论 5 5