implicit关键字详解

implicit

  1. implicit是scala中的一个关键字,下面从五个方面介绍下implicit
    1. 隐式转换函数:implicit def int2str(x:Int):String = x.toString
    2. 隐式类:implicit class Student(x: Int) {    }
    3. 隐式参数:def Student[T](x:T,y:T)(implicit ordered: Ordering[T]):Int = ordered.read(x,y)
    4. 隐式值:implicit val x: Int = 0
    5. 隐式对象:implicit object obj {}
  2. Scala支持两种形式的隐式:
    1. 隐式值:用于给方法提供参数(隐式转换函数,隐式对象都可以作为隐式值为方法提供隐式参数)
    2. 隐式视图:用于对象类型间的转换使函数的调用能够编译通过(隐式转换函数,隐式类都可以看成是隐式视图的隐式转换)
  3. 作用:通过隐式转换可以极大的减少代码量,让编译器去去搜索作用域内的implicit修饰信息进行隐式转换、隐式赋值
  4. implicit修饰的都必须满足无歧义规则
  5. 隐式转换的存放的地点:需要导入包 :import com.bigdata.study.scala._
    1. 当前程序可见作用域
    2. 原类型的伴生对象中
    3. 其他object中

隐式转换函数

  1. 隐式转换函数:使用implicit关键字修饰的函数
  2. 隐式转换的前提:
    1. 隐式转换函数只接受一个参数,对于接受多参数的隐式函数来说就没有隐式转换的功能
      implicit def int2str(x:Int):String = x.toString // 正确
      implicit def int2str(x:Int,y:Int):String = x.toString // 错误
    2. 不支持嵌套的隐式转换
      class A{
           def hi = println("hi")
          }
      
          implicit def int2str(x:Int):String = x.toString 
      
          implicit def str2A(x:Int,y:Int):A = new A
      
          "str".hi  // 正确
          1.hi      // 错误
    3. 不能存在二义性,即同一个作用域不能定义两个相同类型的隐式转换函数(即是不能存在两个都是将类型a转换成类型b的函数)
      implicit def int2str(x:Int):String = x.toString 
      implicit def anotherInt2str(x:Int):A = x.toString
    4. 代码能够在不使用隐式转换的前提下能编译通过,就不会进行隐式转换(即当表达式在编译不通过的情况下才会调用隐式转换,如果编译通过就不调用)
  3. 一个对象调用一个函数编译不通过只有两个原因:a.fun(b) 
    1. 当方法中的参数的类型b与目标类型不一致时
    2. 当对象a调用类中不存在的方法或成员时
  4. 隐式转换的顺序:隐式转换使表达式通过编译的顺序是 b到a.(先对b进行转换看是否通过,如果不通过在对a进行转换,如果都转换之后还不通过就报错)
  5. 隐式转换的作用:
    1. 编译器会在当前作用域寻找合适的隐式转换使将a或者对象b进行转换类型使编译通过
    2. 就是扩展已有的类,在不修改原有类的基础上为其添加新的方法、成员(把一种类型自动转换成另外一种类型,进而使用另外一种类型中的属性和方法)

  例子:

object ImplicitDemo {
    // TODO:定义隐式转换函数,地点一 -> 当前程序可见作用域
    implicit def man2SuperMan(man: Man): SuperMan = new SuperMan(man.name)
    def main(args: Array[String]): Unit = {
        // 平时的时候,普通人, 该上学的上学
        val man = new Man("super")
        // 怪兽出现,毁灭人类,普通人变身奥特曼,吊打怪兽
        import com.erongda.bigdata.scala.oop.demo07.AA._
        man.emitLaser()
    }
}

隐式类

  1. Scala2.10引入了一种叫做隐式类的新特性。隐式类指的是用implicit关键字修饰的类。在对应的作用域内,带有这个关键字的类的主构造函数可用于隐式转换。
  2. 限制条件:
    1. 只能在别的trait/类/对象内部定义。
      object Test {implicit class person(x: Int)} // 正确! 
      implicit class person(x: Double) // 错误!
    2. 构造函数只能携带一个非隐式参数(虽然我们可以创建带有多个非隐式参数的隐式类,但这些类无法用于隐式转换。)
       implicit class Test(str: String) // 正确!
       implicit class Test[T](str: String, index: Int) // 错误!
       implicit class Test[T](str: String)(implicit index: Index) // 正确!
    3. 在同一作用域内,不能有任何方法、成员或对象与隐式类同名。(注意:这意味着隐式类不能是case class。)
      object Test{
        def main(args: Array[String]): Unit = {
          implicit class Test(x: Int) // 错误!
          val x = 1
          implicit class x(y: Int) // 错误!
          implicit case class Baz(x: Int) // 错误!
        }
      }
  3. 隐式类和隐式转换函数区别:都是实现隐式转换,各有优点(比如:a想添加b方法)
    1. 隐式转换函数:首先创建一个有b方法的类c ,在写一个隐式转换函数fun(a)将对象a变成对象c
    2. 隐式类:构造一个隐式类c(a),将参数a的类型转换成自己的类型c,直接调用b方法 
    3. 优缺点:隐式类比隐式转换函数更加简单,但是隐式转换函数的功能更加强大,因为需要多个对象object1,object2,object3添加方法,隐式类需要为每一个对象创建一个隐式类(方法),隐式转换函数只需要创建一个对象(方法),为每个object1,object2,object3添加一个隐式转换函数即可

 

object ImplicitTest {
  class  Man{}
  //隐式类
implicit  class Teacher(man: Man){
  def fly: Unit = {
    println("在教书")
  }
}
  //隐式转换函数
  class Student(man:Man){
    def study: Unit ={
      println("在学习")
    }
  }
implicit def ManToStudent(man:Man)=new Student(man)
  def main(args: Array[String]): Unit = {
    val man = new Man
    man.fly
    man.study
  }
}

隐式参数

  1. 隐式参数:使用关键字implicit进行标识参数就是隐式参数,隐式参数一般和普通的参数放在两个不同的括号中(def student(name:String)(implicit age:Int))
  2. 函数的调用:在调用含有隐式参数的函数时可以不用传递隐式参数,编译器会自动寻找合适的隐式值当做隐式参数,而只有用implict标记过的值、对象、函数才能被找到。
  3. 隐式参数有默认值,可以用赋值,也可以当做一个普通的参数那样进行赋值

寻找隐式值

object ImplicitTest {
  def main(args: Array[String]): Unit = {
    implicit val ages = 12
    def student(name:String)(implicit age:Int): Unit ={
      println(s"$name 今年 $age 岁了")
    }
    student("Tom")
    student("Tom")(15)
  }
}

寻找隐式对象和隐式函数

object ImplicitTest {
  def main(args: Array[String]): Unit = {
//    例如自动寻找隐式对象:
    implicit object Student {
      def Study(s:String) = println(s"好好学习 $s!")
    }
    def test(s:String)(implicit stu: Student.type ) = {
      stu.Study(s)
    }
    test("Tom")   //
//    自动寻找隐式函数:
    implicit def int2str(x: Int): String = x.toString

    def test1(x: Int, fun: String => Unit)
             (implicit age: Int => String) = {
      fun(age(x))
    }
    test1(12, println) // 打印出"12"
  }
}
原文地址:https://www.cnblogs.com/WeiKing/p/11613472.html