Scala隐式转换和泛型

Posted leafgood

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Scala隐式转换和泛型相关的知识,希望对你有一定的参考价值。

1.隐式转换

1.1 什么是隐式转换?

看如下示例

object Scala_Transform {
  def main(args: Array[String]): Unit = {
    val byte_num:Byte = 21
    val int_num:Int = byte_num
    println(int_num)
  }
}

这个能够正常打印,因为能够编译器能够进行自动转换,但如果代码改东西,由int转换成byte

object Scala_Transform {
  def main(args: Array[String]): Unit = {
    val int_num:Int = 21
    val byte_num:Byte = int_num //这里会出错
    println(byte_num)
  }
}

出错原因由Int到Byte没有直接的关系,编译器找不到对应的转换方法。
那么我们提供一个

object Scala_Transform {
  def main(args: Array[String]): Unit = {
    // int转换成byte的方法
    def itbFun(x:Int):Byte = {
      x.toByte
    }

    val int_num:Int = 21
    val byte_num:Byte = itbFun(int_num)//这里会出错
    println(byte_num)
  }
}

但是这样又修改了代码逻辑,那么能否让编译器自己找到转换方法来进行转换呢?这时候只要在方法前加上一个关键字implicit

object Scala_Transform {
  def main(args: Array[String]): Unit = {
    // int转换成byte的方法
    implicit def itbFun(x:Int):Byte = {
      x.toByte
    }

    val int_num:Int = 21
    val byte_num:Byte = int_num
    println(byte_num)
  }
}

编译就会自动找到转换的方法,来进行转换,这个就是隐式转换。

1.2 隐式方法

在函数声明前增加implicit关键字,编译器就能自动识别和自动调用完成类型的转换,这样的方法就叫隐式方法。

object Scala_Transform {
  def main(args: Array[String]): Unit = {
    val person = new Person
    person.info()
    
    // 因为需求变化,我们需要在原有信息打印基础上加上性别地址address信息
    // 我们可以使用隐式方法来完成这个
    implicit def transformFun(person: Person): PersonInfoAdd ={
      new PersonInfoAdd
    }
    person.updateInfo()
    
  }
  
  class Person {
    def info(): Unit ={
      println("name:xxx age:xxx")
    }
  }
  
  // 扩展类
  class PersonInfoAdd{
    def updateInfo():Unit = {
      println("address:xxxx")
    }
  }
  
}

在使用时需要注意,当前范围内,相同的转换规则只能有一个。
隐式转换方法会在第一次编译出错时,选择隐式转换,所以也叫二次编译。

1.3 隐士参数和隐士变量

implicit除了修饰方法外,还可以修饰参数,这个就是隐式参数。
当我们预先知道方法的参数会发生变化时,我们可以使用implicit关键来修饰的这个参数。
隐士变量,就是编译器自动找到并传递的参数值
示例

object Scala_Transform {
  def main(args: Array[String]): Unit = {
    // 登录账号,最开始使用默认密码123456登录,后期使用用户自定义的密码登录
    def loginFun(user:String)(implicit pwd:String="123456"): Unit ={
      println(s"用户:$user, 密码:$pwd")
    }

    // 隐士变量
    implicit val pwd:String = "123123"

    // 使用隐士参数时,后面省略小括号
    loginFun("user1") // 输出结果  用户:user1, 密码:123123

    // 不省略小括号,会传递默认值或者自定义参数,而不使用隐式变量
    loginFun("user1")() // 输出结果 用户:user1, 密码:123456
    loginFun("user1")("666666") // 输出结果 用户:user1, 密码:666666
  }
}

1.4 隐士类

隐式类是2.10版本增加的
示例

object Scala_Transform {
  def main(args: Array[String]): Unit = {
    val person = new Person
    person.info()

    person.updateInfo()
   // 隐士类的查找顺序
   // 1)第一个是当前作用域
   // 2)上级作用域
   // 3)当前类所在的包对象
   // 4)父类
   // 5)特质
   
   // 一般我们使用隐士类转换时,可以直接导入
   
  }

  class Person {
    def info(): Unit ={
      println("name:xxx age:xxx")
    }
  }

  // 隐式类
  // implicit修饰,构造参数要存在且只有一个,用于类型转换
  implicit class PersonInfoAdd(person: Person){
    def updateInfo():Unit = {
      println("address:xxxx")
    }
  }

}

2.泛型

2.1 Scala泛型

泛型用于指定方法或类可以接受任意类型参数,参数在实际使用时才被确定,泛型可以有效地增强程序的适用性,使用泛型可以使得类或方法具有更强的通用性。
Scala中泛型和Java泛型一致,但功能更加强大,声明时使用[]

2.2 泛型类、泛型方法

泛型类:指定类可以接受任意类型参数。
泛型方法:指定方法可以接受任意类型参数。

示例

object Scala_Generic {
  def main(args: Array[String]): Unit = {
    
  }
  // 使用[]声明泛型
  class DemoClass[T] {
    private val list:List[T] = Nil
  }

}

2.3 泛型转换

2.3.1 泛型不可变

示例

object Scala_Generic {
  def main(args: Array[String]): Unit = {
    // 泛型不可变
    val demo1:Demo[Student] = new Demo[Student] // 正确
    val demo2:Demo[Student] = new Demo[Person] //错误
    val demo3:Demo[Student] = new Demo[Student_Of_BJ] //错误
    
    // 从结果上看,在我们常规声明,没有采用其他途径时,泛型是不可变的

  }
  class Demo[T] {
  }

  class Person{
  }

  class Student extends Person{
  }

  class Student_Of_BJ extends Student{
  }

}

2.3.2 泛型协变

Scala可以让上面代码 "val demo3:Demo[Student] = new Demo[Student_Of_BJ]" 能够通过的,也就是说,泛型可以将子类型当成父类型使用,这个是泛型的协变
示例代码

object Scala_Generic {
  def main(args: Array[String]): Unit = {
    // 泛型协变
    val demo1:Demo[Student] = new Demo[Student] // 正确
    val demo2:Demo[Student] = new Demo[Person] //错误
    val demo3:Demo[Student] = new Demo[Student_Of_BJ] //正确

  }
  // 非常简单,只要在泛型前用"+"
  class Demo[+T] {
  }

  class Person{
  }

  class Student extends Person{
  }

  class Student_Of_BJ extends Student{
  }

}

2.3.4 泛型逆变

泛型可以将父类型当成子类型使用,使用[-T] 声明泛型

object Scala_Generic {
  def main(args: Array[String]): Unit = {
    // 泛型逆变
    val demo1:Demo[Student] = new Demo[Student] // 正确
    val demo2:Demo[Student] = new Demo[Person] // 正确
    val demo3:Demo[Student] = new Demo[Student_Of_BJ] //错误
    
  }
  // 加个减号即可
  class Demo[-T] {
  }

  class Person{
  }

  class Student extends Person{
  }

  class Student_Of_BJ extends Student{
  }

}

2.3.5 泛型的上限与下限

在指定泛型类型时,有时需要界定泛型类型的范围,而不是接收任意类型。
Scala的上下边界特性允许泛型类型是某个类的子类,或者是某个类的父类;
(1) U >: T
这是类型下界的定义,也就是U必须是类型T的父类(或本身,自己也可以认为是自己的父类)。
(2) S <: T
这是类型上界的定义,也就是S必须是类型T的子类(或本身,自己也可以认为是自己的子类)。

示例

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

  }
  class Person{
  }

  class Student extends Person{
  }

  class Student_Of_BJ extends Student{
  }
  
  class Demo{
    // 泛型上限
    def fun1[T<:Student](t:T)= {}
    // 泛型下限
    def fun2[T>:Student](t:T)= {}
  }

}

以上是关于Scala隐式转换和泛型的主要内容,如果未能解决你的问题,请参考以下文章

Scala异常 隐式转换 泛型

Scala:从泛型类型到第二泛型类型的隐式转换

Scala学习之路

Scala 类型类模式和泛型方法

结果类型是泛型类型上的类型投影的隐式转换

Scala:泛型和隐式