【scala系列】12、隐式转换、视图界定


1. 隐式转换

  • 隐式转换是scala中一种特殊的功能,能在不改动已有class设计的情况下为class添加新的方法
  • 隐式转换是把一种类型安全地转成另一种类型,原数据类型将拥有新的数据类型的所有方法,也可以看成是对类的一种增强
  • 定义隐式转换的关键字是 implicit
  • 隐式转换的常用命名方式是 one2one
  • 隐私转换分为两种:
    1. 隐式转换函数
    2. 隐式转换值

1.1 隐式转换函数


class ImplicitDemo1_1(var name: String)

class ImplicitDemo1_2(var name: String)

class ImplicitDemo1_3(var name: String)


/**
  * 扩大隐式转换的作用域
  * 我们可以将隐式转换函数或者值定义在object对象中,来扩大隐式转换的作用域
  * 以后多个地方使用到的话,我们直接可以使用import 将对应的隐式转换函数或者值导入即可
  * 注意:y隐式转换函数或者值只能定义在object对象中
  *
  */
object ImplicitDemo1_4{
  /**
    * 隐式转换函数
    * 将函数放在 object 总增大其作用域
    * 隐式转换函数要在使用前定义或引用
    */

  implicit def any2ImplicitDemo1_1(any: Any) = {
    // 判断传过来的数据类型 如果是ImplicitDemo1_2
    if (any.isInstanceOf[ImplicitDemo1_2]) {

      // 自动转换为 ImplicitDemo1_1
      val i2 = any.asInstanceOf[ImplicitDemo1_2]
      new ImplicitDemo1_1(i2.name)

    } else if (any.isInstanceOf[ImplicitDemo1_3]) {
      val i3 = any.asInstanceOf[ImplicitDemo1_3]
      new ImplicitDemo1_1(i3.name)
    } else {
      null
    }
  }
}

object ImplicitDemo1 {

  def whichClass(p: ImplicitDemo1_1) = {
    if (p != null) {
      println("is ImplicitDemo1_1:" + p.name)
    } else {
      println("no ImplicitDemo1_1:")
    }
  }

  def main(args: Array[String]): Unit = {
    val i1 = new ImplicitDemo1_1("xiaom")
    val i2 = new ImplicitDemo1_2("xioah")
    val i3 = new ImplicitDemo1_3("xioag")
    //编译器运行时会检测有没有隐式转换函数 去转换类型
    whichClass(i1) //is ImplicitDemo1_1:xiaom

    // 引入隐士转换
    import ImplicitDemo1_4.any2ImplicitDemo1_1
    // 未定义隐式转换时传送参数类型不匹配无法传送 i2, 定义后即可使用
    whichClass(i2) //is ImplicitDemo1_1:xioah
    whichClass(i3) //is ImplicitDemo1_1:xioag

  }
}

1.2 隐式参数


class ImplicitDemo2_1(var name:String){
  def write(content:String)= println(s"name=$name, content=$content")
}

object ImplicitDemo2 {
  /**
    * 在方法中被implicit修饰的参数被称为隐式参数
    * @param name
    * @param p
    */
  def singForExam(content:String)(implicit i1:ImplicitDemo2_1)={
    i1.write(content)
  }

  def main(args: Array[String]): Unit = {

    // 隐式参数必须在上下文中有用隐式定义的对应类型
    implicit val i1 = new ImplicitDemo2_1("你好")
    //implicit val i2 = new ImplicitDemo2_1("hello")//一起多个会报错
    singForExam("小明") //name=你好, content=小明

    //i1.write("xiaom") //name=你好, content=xiaom

    //implicit val i3 = new ImplicitDemo2_1("hello")//一起多个会报错
    //singForExam("黑") //name=你好, content=小明
  }
}

1.3 隐式类型转换


object ImplicitDemo3 {

  // 需要时把String->Int
  implicit def foo(s:String):Int = Integer.parseInt(s)

  //  做求和计算
  def add(a:Int, b:Int) = a+b

  def main(args: Array[String]): Unit = {

    // 计算时先把"100"隐式转换为100
    println(add("100",8)) // 108
  }
}

1.4 隐式为Int增加next 与求阶乘方法


object ImplicitDemo3_1 {

  // 隐士转换函数 为 Int 类型增加next方法
  implicit def next(n: Int) = new {
    def next = n + 1
  }


  // 定义阶乘函数
  def pow(n: Int, m: Int): Int = if (m == 0) 1 else n * pow(n, m - 1)

  // 定义隐式转换函数 **
  implicit def foo(n: Int) = new {
    def **(m: Int) = pow(n, m)
  }

  def main(args: Array[String]): Unit = {

    println(10.next) // 11

    println(2**10) // 1024

  }
}

1.5 隐式对类的增强

object ImplicitDemo4 {
  implicit def file2RichFile(file:File):RichFile = new RichFile(file)
  def main(args: Array[String]): Unit = {
    val file = new File("/opt/apache-maven-3.6.2/conf/settings.xml")
    file.read()
  }
}

/**
  * 在这里将file 转换为RichFIle 相当于对类的增强
  * @param file
  */
class RichFile(var file:File){
  def read()={
    val content = Source.fromFile(file).mkString
    println(content)
  }
}

2. 视图界定

  • 视图界定用 <% 来表示 (T <% Class1),表示 T 只能是 Class1 的子类或者 T 能隐式转换成 Class1 类,
  • 视图界定是对泛型中类的上边界的一种增强

class Human(var name:String){
  def sayHello(): Unit ={
    println(s"hello, I'm $name")
  }
  def makeFriends(p:Human)={
    sayHello()
    p.sayHello()
  }
}

class Student(name:String) extends Human(name)

class Cat(var name:String){
  def sayHello(): Unit ={
    println(s"I'm a cat name is $name")
  }
}
//泛型T 只能是Human 及其子类,或者T类能够隐式的转换成Human的类型
class Party [ T<% Human](p1:T,p2:T){
  p1.makeFriends(p2)
}

object ImplicitDemo05 {
  def main(args: Array[String]): Unit = {
    val human1 = new Human("小明")
    val human2 = new Human("小红")
    val party1 = new Party[Human](human1,human2)
    /**
      * hello, I'm 小明
      * hello, I'm 小红
      */

    val s1 = new Student("小学生")
    val s2 = new Student("中学生")
    val party2 = new Party[Student](s1,s2)
    /**
      * hello, I'm 小学生
      * hello, I'm 中学生
      */



    val c1 = new Cat("加菲猫")
    val c2 = new Cat("小花猫")

    // 对Cat 类进行隐式转换
    implicit def cat2Human(cat:Cat):Human ={
      new Human(cat.name)
    }

    //因为Cat 不是Human的子类 所以必须用隐式转换才能使用
    val party3 = new Party[Cat](c1,c2) 

    /**
      * hello, I'm 加菲猫
      * hello, I'm 小花猫
      */
  }
}

文章作者: hnbian
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 hnbian !
评论
 上一篇
【scala系列】13、Scala IO 、 XML 【scala系列】13、Scala IO 、 XML
1. IOimport java.io._, java.nio._ object IODemo{ def main(args: Array[String]): Unit = { val path = "D:\\data\\oo
2020-04-20
下一篇 
【scala系列】11、泛型、上下边界、协变、逆变 【scala系列】11、泛型、上下边界、协变、逆变
1. 泛型类 泛型类就是在类的声明中,定义一些泛型类型。然后类内部的字段或者方法就可以使用这些泛型类型 使用泛型类通常是需要对类中的某些成员(字段、方法中的参数或变量)进行统一的类型限制,这样可以保证程序更好的健壮性和稳定性 如果不使用泛型
2020-04-15
  目录