scala 隐式转换 及Spark 源码解析

隐式转换,是scala当中一个重要的特性,今天我们结合自己的例子和spark源码,争取对隐式转换有一个更加深入的了解。

关于implicit有3种使用方式,implicit def、implicit class以及implicit 参数

首先看一下implicit def的用法:

object implicitTest {
  class Man(val name: String){
    def work(){println(name + " is working!")}
  }

  class Woman(val name: String){
    def shop(){println(name + " is shopping!")}
  }

  class Child(val name: String){
    def play(){println(name + " is playing!")}
  }

  implicit def manToWoman(man: Man) = new Woman(man.name)
  implicit def manToChild(man: Man) = new Child(man.name)

  def main(args: Array[String]): Unit ={
    val man = new Man("Tom")
    val woman = new Woman("Lily")
    val child = new Child("baby")
    man.work()
    man.shop()
    man.play()

  }
}

在上面的代码当中,我们定义了3个class,Man、Woman、Child,他们之间没有任何继承关系。下面的main函数当中,我们声明了Man、Woman、Child,各一个实例,我们考虑,作为男人来讲,是不是也不一定只能是工作,适当的休闲和娱乐是不是也是可以的。所以我们做了2个隐式转换的函数,manToWoman和manToChild,需要注意的是,这两个函数名其实一点都不重要,我们只是希望看起来更容易理解一些,你写个aaa或者bbb,一点问题都没有。

编译过程大概是这样的:

1、编译man.shop(),发现并没有shop方法,即将报错

2、报错之前,搜索一下作用域内,有没有隐式转换函数,能够支持man对shop的调用,找到了manToWoman

3、把man变成woman,调用shop方法

 

之后再看一下implicit class的用法:

object implicitTest {
  class Man(val name: String){
    def work(){println(name + " is working!")}
  }

  class Woman(val name: String){
    def shop(){println(name + " is shopping!")}
  }

  class Child(val name: String){
    def play(){println(name + " is playing!")}
  }

  implicit class ManConvert(m: Man){
    def shop() = new Woman(m.name).shop()
    def play() = new Child(m.name).play()
  }

  def main(args: Array[String]): Unit ={
    val man = new Man("Tom")
    val woman = new Woman("Lily")
    val child = new Child("baby")
    man.work()
    man.shop()
    man.play()

  }
}

这个当中实现的效果看起来和前一种差不多,其实它的语义是完全不同的。编译过程大概是这样的:

1、编译man.shop(),发现并没有shop方法,即将报错

2、报错之前,搜索一下作用域内,看看有没有隐式转换类,能够为man提供shop方法,找到了ManConvert

3、将man转换为ManConvert,执行shop方法。

 

最后我们再看一下implicit参数的用法:

object implicitTest {
  class Man(val name: String){
    def work(){println(name + " is working!")}
    def marry(implicit w: Woman){println(name + " marryed " + w.name)}
  }

  class Woman(val name: String){
    def shop(){println(name + " is shopping!")}
  }

  def main(args: Array[String]): Unit ={
    val man = new Man("Tom")
    implicit val woman = new Woman("Lily")
    man.marry

  }
}

我们为Man增加了一个marry的方法,它的参数w是implicit的,然后调用的时候,我们先在前面声明了一个implicit 类型的woman,之后调用marry但是不指定参数,这样是不会报错得到。但是如果我们在marry的前面声明了2个implicit的woman,那么marry还是会报错的。

换成人类的语言来解释这件事:一个男人要结婚,如果指定结婚对象,那没问题,如果没指定,那就看看身边有没有适合的结婚对象,有的话,就直接生米煮成熟饭,可是如果身边有2个,好吧,我也不知道该娶哪个!

 

结合Spark源码,我们来深入理解一下implicit,看下面这段代码:

val rdd = sc.textFile("hdfs://master:9000/woozoom/mavlink1.log", 12).zipWithIndex()
rdd.sortByKey()

看起来是达到目的了,可是这个sortByKey的确切含义究竟是什么,倒序?正序?能不能自定义排序原则?去找一下spark的api文档吧,找到RDD类,查找sortByKey方法,可是,居然,居然没有,只有sortBy,没有sortByKey。懵逼了~~~~~~

直到我了解了implicit这回事,并且在RDD的源码当中我们找到了下面这段:

  implicit def rddToOrderedRDDFunctions[K : Ordering : ClassTag, V: ClassTag](rdd: RDD[(K, V)])
    : OrderedRDDFunctions[K, V, (K, V)] = {
    new OrderedRDDFunctions[K, V, (K, V)](rdd)
  }

总结:上面我们对scala的implicit做了比较全面的了解,这样的工作,对scala和spark的学习和理解,非常重要(不然容易懵逼~~~~~~~)。

但是,我要说但是,凡事都有其两面性,implicit在带来代码的紧凑和精炼的同时,负作用就是可读性极差;特别是在工作的初级阶段,我是强烈不建议我们团队内部大量的使用implicit。在我看来,多写两行代码,显式的转换一下,真的不是什么大事!

 

转载于:https://my.oschina.net/dongtianxi/blog/746380

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值