Scala 隐式转换简明教程

2019-10-30 19:14:44 浏览数 (1)

前言

对于 Spark 开发者来说 Scala 终究是个绕不过去的坎, 而 对于 Scala ,隐式转换终究也是一个绕不过去的坎。 所以本文就以一种尽可能简单的方式带大家来理解一下 Scala 的隐式转换。

Scala隐式转换 是什么?

  • 隐式转换 这里我没有找到具体的定义, 这里我们就用大白话来说一下, 如果我们想让一台汽车具有挖土机的功能, 那么我们需要给这个汽车装上一个挖机铲, 如果装这个挖机铲需要我自己买来装, 那我们就说是显示转换, 如果这个挖机铲有人给我自动装上了, 并且我都不知道到底这个人是谁,是怎么给我装上的, 那这就是隐式转换。 ok,这里我们先记住这个小栗子, 后面我们用代码来实现的时候你就会有更进一步的理解

Scala隐式转换 的使用

  • 隐式参数 二话不说,我们先上个列子, 然后再来解释:
代码语言:javascript复制
 def main(args: Array[String]): Unit = {
      //定义一个隐式参数
      implicit val i_car: String = "*小汽车*"

      def upgradeExcavator(implicit car:String): Unit ={
        println("我将把 " car " 升级成 挖机")
      }
      //显示转换
      upgradeExcavator(i_car)
      //隐式转换
      upgradeExcavator
    }
  1. 我们定义了一个隐式参数 i_car.
  2. 接着我们定义了一个方法upgradeExcavator, 并接受一个参数,打印一句将传入的参数升级为 挖土机
  3. 然后我们显示的传入参数 i_car,调用方法 upgradeExcavator(i_car), 控制台打印我将把 *小汽车* 升级成挖机
  4. 然后我们直接调用方法 upgradeExcavator,不传入任何参数 控制台也会打印我将把 *小汽车* 升级成挖机。 很明显,系统自己将我们的 i_car 当做了参数传入。

我们仔细观察就会发现,我们定义 i_car的时候使用了 implicit关键字修饰, upgradeExcavator的参数一样使用到了 implicit关键字修饰, 当我们调用一个方法,其参数被 implicit关键字修饰 的时候, 如果我们不传入参数,那么该方法就会去其作用域内寻找一个符合该类型的参数, 作为其默认的传入值

ok,这就是隐式参数,那么我们需要注意的是:

  1. 如果作用域内有多个符合规则的参数会怎么样呢? 报错,因为系统将不知道你要使用的是哪个参数, 这个时候你就只能使用显示转换了。
  2. 如果我需要传入隐式参数,同时也需要传入显示参数呢?怎么办? 这种需求我们需要使用 柯里化 函数才行, 类似这样def upgradeExcavator(car2:String) (implicit car:String)={...} 这里Scala 高阶函数应用不在讨论之列, 所以就不多说了。
  3. implicit 关键字必须放在隐式参数定义的开头, 多个参数只需要在头部标注即可
  • 隐式函数 同样的,我们先上代码
代码语言:javascript复制
  class Car() {
    def name() = {
      "普通小汽车"
    }
  }

  class Excavator(car: Car) {
    def name() = {
      car.name()   " 升级成的 挖土机"
    }
    def dig() = {
      println("我具有挖掘功能")
    }
  }

  def main(args: Array[String]): Unit = {
    implicit def upgradeExcavator(car: Car) = {
      new Excavator(car)
    }

    val car = new Car
    println(car.name())
    car.dig()
  }
  1. 我们定义了一个 Car类,其有一个 name方法返回其名字
  2. 我们定义了一个 Excavator类,其有一个 name方法返回其名字, 和一个挖掘的功能函数dig
  3. 我们创建一个隐式函数,该函数接受一个 Car对象,并返回一个 Excavator
  4. 我们创建一个 Car 实例,打印去名字
  5. 神奇的是,我们竟然可以 car.dig() ,我们的小汽车竟然有挖掘功能

这就是隐式函数,当我们创建了一个对象Car,并调用不属于该对象的方法dig的时候。 那么系统会去作用域内寻找一个隐式函数, 如果他能找到这么一个隐式函数——将 Car转换成 Excavator的函数, 那么你就可以直接把 Car当做Excavator使用

  • 隐式类 隐式类其实和隐式方法很像,我们将上面的代码改一改, 很容易就得到以下这个代码:
代码语言:javascript复制
  class Car() {
    def name() = {
      "普通小汽车"
    }
  }

  implicit class Excavator(car: Car) {
    def name() = {
      car.name()   " 升级成的 挖土机"
    }
    def dig() = {
      println("我具有挖掘功能")
    }
  }

  def main(args: Array[String]): Unit = {
    val car = new Car
    println(car.name())
    car.dig()
  }

我们去掉了隐式方法,将Excavator 修改成了一个隐式类, 那么 当我们创建一个对象 Car,并尝试去调用 dig函数的时候, 系统会去其作用域内寻找是否有这么一个类,其构造函数接受一个 Car, 如果有,那么我们就可以把 car对象直接当Excavator 使用。

OK!到这里 隐式转换的相关使用知识差不多就是这样了, 这里我们多次提到作用域,所以隐式函数什么的, 是可以通过 import 来进行导入的, 这也就是隐式转换可以简化代码的一个重要原因,

本文既然是基于简明二字,所以没有太多的理论, 希望你看完之后会有一点帮助

0 人点赞