scala隐式参数、隐式函数、隐式类详解--关于implicit的大白话

一、隐式参数

1.1 定义

定义一个普通变量,使用 “implicit” 关键字修饰,定义一个函数调用这个变量当参数时,此时这个参数就被称为 隐式参数

隐式参数的作用:减少提供函数参数的数量,让某些参数拥有隐藏的值(隐式变量)

1.2 示例

例①:

implicit val num:Int = 10     //定义一个Int类型的隐式参数
def sum(a:Int)(implicit num :Int):Int={   //隐式参数放入到普通函数中
  a+num
}
//测试
println(sum(10))    //20

注:

  • 这里定义的变量名是 num ,但是传入到函数当中,隐式参数名可以不为 num,随便起什么名字都可以,只要是 Int 类型就可以
  • 在一个类中,定义同一类型的隐式参数只能有一个,即函数参数列表中同一类型的隐式参数也只能为一个,多了会打架,比如定义了两个Int类型的变量当参数,implicit val a:Int = 10, implicit val b:Int = 20 ,传入到函数中scala编译就不知道用哪个参数了
  • 在一个类中,不同类型的隐式参数可以传入到函数当中
  • scala中函数的传参级别: 函数列表传参 > 隐式参数 > 默认值

例②:

implicit val num:Int = 10     //定义一个Int类型的隐式参数num
implicit val say:String="Hello scala"   //定义一个String类型的隐式参数say
def sum(a:Int)(implicit b :Int,str:String):Int={   //请注意这里传参时,我将 num 改成了 b,say 改成了str ,证明隐式参数只认类型
	println(str)
  	a+b
}
//测试
println(sum(10))  
  
//控制台输出:
//Hello scala
//20

二、隐式函数

2.1 定义

通常我们所说的隐式函数也称为 隐式转换,是使用 implicit 修饰的函数

作用: 可以通过一个隐式函数将一种类型转变为另一种类型

隐式转换有两种应用场景:

  • 类型转换,隐式转换为期望类型
  • 类型增强

2.2 示例

①:类型转换
在java中,当我们申明一个变量a 为 Int 类型,赋值为 3.5 ,这时就会直接报错,scala也一样
在这里插入图片描述
但是在scala中定义一个隐式函数,函数体是将传入的 Double 类型使用 toInt 方法转为 Int 类型就可以解决这个问题

implicit def doubleToInt(obj:Double) = obj.toInt   //定义隐式函数
val a:Int = 3.5    //写的时候scala就调用了隐式函数 doubleToInt 进行类型转化 

常用的类型转换:

implicit def doubleToString (obj:Double):String=obj.toString
implicit def intToString(obj:Int):String=obj.toString
implicit def stringToInt(obj:String):Int=Integer.parseInt(obj)

对象的类型转换见下文 -----> 3.2示例

②:类型增强
比如说 1+true 这个表达式,我们想让 true当作 1计算, false当作 0计算。
Int 类型与boolen类型是无法相加的,编译器肯定会报错
在这里插入图片描述
此时,我们可以定义一个隐式函数,使 “true=1,false=0” ,此时便可提供一个隐式函数,使得Int+Boolean成立

implicit def booleanToInt(obj:Boolean)=if(obj) 1 else 0
//测试
val a=1+true
println(a)  //2

注: 隐式转换的发生时机

  • 当方法中的参数的类型与目标类型不一致时

  • 当对象调用类中不存在的方法或成员时,编译器会自动将对象进行隐式转换

三、隐式类

3.1 定义

隐式类指的是用implicit关键字修饰的类。在对应的作用域内,带有这个关键字的类的主构造函数可用于隐式转换。

3.2示例

现在有一个需求:有一个 Person 类,含有work()方法,有一个 Student 类,含有study()方法,在不使用继承的情况下,要求创建一个Person类的对象,可以直接调用Student类里的study()方法?

方法①: 使用 隐式类 ,将Student类定义为隐式类,这样在 new Person对象的时候, 编译器会默认在Student的主构造方法中传入Person对象,再转型为Student对象,这样新建的Person对象就有了双重身份,可以随便调用这两个类中的方法
代码如下:
创建一个scala class文件: Person

 class Person() {    //定义一个主类:Person 有个work方法
  def work()={
    println("人每天都要工作")
  }
}

object Test1{
 implicit class Student(obj:Person){   //在object中定义一个隐式类:Student 有个study方法
   def study()={               //圈重点:主构造方法传入的类型必须要有----->  Person          
     println("喜欢学习scala")
   }
 }

  def main(args: Array[String]): Unit = {
    val person: Person = new Person    //在main方法中new一个Person对象
    person.work()
    person.study()   //可以看到可以直接调用Student中的study()方法
  }
}

注:

  • 创建隐式类,主构造函数中必须要引入一个目标类当参数,且隐式类必须要在 object 中创建
  • 本文是将隐式类与目标类写在了一个scala文件中,当隐式类写在其他文件中,调用时引入该隐式类所在的包即可

方法②: 使用 隐式函数 转换,创建Person对象时,编译器默认会将Person对象转为Student对象,从而使得新建的Person对象有了双重身份,可以随便调用这两个类中的方法
代码如下:
创建一个scala class文件: Person

class Person() {    //定义一个主类:Person 有个work方法
  def work()={
    println("人每天都要工作")
  }
}

class Student(){   //定义一个普通类:Student 有个study方法
  def study()={               
    println("喜欢学习scala")
  }
}

object Test1{

  //圈重点:定义一个隐式函数,将 Person 转为 Student
  implicit def personToStudent(obj:Person):Student = new Student
  
  def main(args: Array[String]): Unit = {
    val person: Person = new Person    //在main方法中new一个Person对象
    person.work()
    person.study()   //可以看到可以直接调用Student中的study()方法
  }
}

注:

  • 使用隐式函数,Studnet类只需定义为一个普通类即可
  • Person类可以使用多个隐式函数转型,从而使用其他类中的方法

猜你喜欢

转载自blog.csdn.net/and52696686/article/details/107618593
今日推荐