有时候我们看scala代码的时候,会发现明明没有这个类的类型或者函数,甚至是没有这个类,编译器不仅没有报错,程序还可以正常运行,其实这里就用到了scala的隐式转换。
隐式函数
当我们调用一个对象的方法的时候,但是这个对象并没有这个方法,此时就会触发隐式转换,会把这个对象偷偷的转换为具有这个方法的对象。
比如下面的例子,小鸡可以走路也可以跑,但是它也想像小鸟一样飞,但是它有没有这个功能。我们可以在不对小鸡整改的基础上,引入ChickenImplicit,让小鸡可以隐式的调用Bird的fly方法,让它可以像小鸟一样飞。
object ImplicitDemo1 {
def main(args: Array[String]): Unit = {
import ChickenImplicit._
val chicken = new Chicken()
chicken.work()
chicken.run()
// 隐式转为Bird,并调用Bird的fly方法
chicken.fly()
}
}
class Chicken() {
def work(): Unit = {
println("小鸡在走")
}
def run(): Unit = {
println("小鸡在跑")
}
}
class Bird {
def fly(): Unit = {
println("小鸟在飞")
}
}
object ChickenImplicit {
implicit def chicken2Bird(c: Chicken): Bird = new Bird()
}
上面是额外的定义ChickenImplicit,但是有时候我们可以直接在同一个类里定义,这样局不用加import,具体用哪种还是要看实际场景。
object ImplicitDemo2 {
def main(args: Array[String]): Unit = {
val chicken = new Chicken2()
chicken.work()
chicken.run()
// 隐式转为Bird,并调用Bird的fly方法
chicken.fly()
}
implicit def chicken2Bird(c: Chicken2): Bird2 = new Bird2()
}
class Chicken2() {
def work(): Unit = {
println("小鸡在走")
}
def run(): Unit = {
println("小鸡在跑")
}
}
class Bird2 {
def fly(): Unit = {
println("小鸟在飞")
}
}
隐式参数
比如我们要调用方法,打印我们传递的参数,我们是这样写的:
def main(args: Array[String]): Unit = {
printInfo1("aaa") // aaa
}
def printInfo1(str: String): Unit = {
println(str)
}
如果我们调用方法的时候,如果不想传递参数,我们可以这样:
在方法里指定默认值
def main(args: Array[String]): Unit = {
printInfo2("bbb") // bbb
printInfo2() // default
}
def printInfo2(str: String = "default"): Unit = {
println(str)
}
如果通过隐式参数,那我们就可以这样:
这里的方法不加括号也是可以的。由于是通过类型来匹配隐式值的,所以在一个作用域中,同一个类型只能有一次,并且他的优先级高于默认的,所以没有传递参数的时候,打印的implicit。
def main(args: Array[String]): Unit = {
implicit val str: String = "implicit"
printInfo3("ccc") // ccc
printInfo3() // default
printInfo3 // implicit
}
def printInfo3(implicit str: String = "default"): Unit = {
println(str)
}
总结
当我们需要隐式转换的时候,我们就需要用implicit
关键字。
隐式转换的时候,他会先全局的查找是否有匹配的方法或者参数,如果没有再考虑隐式转换。
由于隐式参数是根据类型的,所以同一作用域不能定义多个同一个类型的,并且默认值是优先于默认的。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。