Scala隐式转换
Posted 难以言喻wyy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Scala隐式转换相关的知识,希望对你有一定的参考价值。
目录
隐式转换:
当编译器第一次编译失败的时候,会在当前的环境中查找能让代码编译通过的方法,用
于将类型进行转换,实现二次编译,这种过程由编译器完成,叫做隐式转换或者自动转换。
隐式函数:
函数定义前加上implicit声明为隐式转换函数。
当编译错误时,编译器会尝试在当前作用域范围查找能调用对应功能的转换规则,这个过程由编译器完成,称之为隐式转换或者自动转换。
隐式转换可以在不需改任何代码的情况下,扩展某个类的功能
案例:需求:通过隐式转化为 Int 类型增加方法。
隐式参数
普通方法或者函数中的参数可以通过 implicit 关键字声明为隐式参数,调用该方法时, 就可以传入该参数,编译器会在相应的作用域寻找符合条件的隐式值。 集合排序方法的排序规则就是隐式参数。
他的作用就是减少提供函数参数的数量,让某些参数拥有隐藏的值(隐式变量)
发生时机:
- 1、当方法中的参数的类型与目标类型不一致时
- 2、当对象调用类中不存在的方法或成员时,编译器会自动将对象进行隐式转换
(1)同一个作用域中,相同类型的隐式值只能有一个
(2)编译器按照隐式参数的类型去寻找隐式值,喝隐式值的名称没有关系
(3)隐式参数优先于默认参数,小于方法传值参数
(也就是说隐式参数和默认参数可以同时存在,加上默认参数之后其实就相当于两个不同
优先级的默认参数)
隐式参数有一个很淦的点:
- 如果参数列表中只有一个隐式参数,无论这个隐式参数是否提供默认参数,那么如果要用这个隐式参数就应该将调用隐式参数的参数列表连同括号一起省略掉。如果调用时又想加括号可以在函数定义的隐式参数列表前加一个空参数列表(),那么()将使用隐式参数,()()将使用默认参数(如果有,没有肯定编不过),()(arg)使用传入参数。
- 也就是说一个隐式参数时通过是否加括号可以区分隐式参数、默认参数、传入参数三种情况。
- 那么如果多参数情况下:隐式参数、默认参数、普通参数排列组合在一个参数列表中混用会怎么样呢?没有试验过.
可以进一步简写隐式参数,在参数列表中直接去掉,在函数中直接使用implicity[Type](Predef中定义的)。但这时就不能传参数了,相当于一个在自己作用域范围内起作用的全局量?
案例:
案例2:
输出结果:
隐式类:
在 Scala2.10 后提供了隐式类,可以使用 implicit 声明类,隐式类的非常强大,同样可以
扩展类的功能,在集合中隐式类会发挥重要的作用。
也就是说编译不通过,就可能会将数据直接传给构造转换为对应的类
(1)其所带的构造参数有且只能有一个
(2)隐式类必须被定义在“类”或“伴生对象”或“包对象”里,即隐式类不能是顶 级的。
案例:
隐式解析机制:
(1)首先会在当前代码作用域下查找隐式实体(隐式方法、隐式类、隐式对象)。(一 般是这种情况)
(2)如果第一条规则查找隐式实体失败,会继续在隐式参数的类型的作用域里查找。 类型的作用域是指与该类型相关联的全部伴生对象以及该类型所在包的包对象。
隐式转换作用:
隐式函数和隐式类可以用于扩充类的功能,常用语比如内建类Int Double String这种。
隐式参数相当于就是一种更高优先级的默认参数。用于多个函数需要同一个默认参数时,就不用每个函数定义时都写一次默认值了。
2021年大数据常用语言Scala(三十八):scala高级用法 隐式转换和隐式参数
目录
隐式转换和隐式参数
隐式转换和隐式参数是scala非常有特色的功能,也是Java等其他编程语言没有的功能。我们可以很方便地利用隐式转换来丰富现有类的功能。
隐式转换
来看一个案例,
object SuperIntDemo {
def main(args: Array[String]): Unit = {
val a:Int = 1
// 使用中缀调用to方法
println(a to 10)
}
}
通过查看Int的源代码,你会惊奇地发现,Int类型根本没有to方法。这难道是让人怀疑人生的大bug吗?
——这其实就是隐式转换的强(gui)大(yi)之处。它在背后偷偷摸摸地帮我们了某种类型转换。
所谓隐式转换,是指以implicit关键字声明的带有单个参数的方法。它是自动被调用的,自动将某种类型转换为另外一种类型。
隐式转换的使用步骤:
在object中定义隐式转换方法(使用implicit)
在需要用到隐式转换的地方,引入隐式转换(使用import)
自动调用隐式转化后的方法
示例:使用隐式转换,让File具备有reada
class RichFile(val f:File) {
// 将文件中内容读取成字符串
def read() = Source.fromFile(f).mkString
}
object MyPredef {
// 定义隐式转换方法
implicit def file2RichFile(f:File) = new RichFile(f)
}
object ImplicitConvertDemo {
def main(args: Array[String]): Unit = {
val f = new File("./data/textfiles/1.txt")
// 导入隐式准换
import MyPredef.file2RichFile
// 调用的其实是RichFile的read方法
println(f.read())
}
}
自动导入隐式转换方法
前面,我们手动使用了import来导入隐式转换。是否可以不手动import呢?
在scala中,如果在当前作用域中有隐式转换方法,会自动导入隐式转换。
示例:将隐式转换方法定义在main所在的object中
class RichFile(val f:File) {
// 将文件中内容读取成字符串
def read() = Source.fromFile(f).mkString
}
object ImplicitConvertDemo {
// 定义隐式转换方法
implicit def file2RichFile(f:File) = new RichFile(f)
def main(args: Array[String]): Unit = {
val f = new File("./data/textfiles/1.txt")
// 调用的其实是RichFile的read方法
println(f.read())
}
}
隐式转换的时机
什么时候会自动执行隐式转换呢?
当对象调用中不存在的方法时,编译器会自动将对象进行隐式转换
当方法中的参数类型与目标类型不一致时
示例:
object ImplicitConvertDemo {
// 定义隐式转换方法
implicit def file2RichFile(f:File) = new RichFile(f)
def main(args: Array[String]): Unit = {
val f = new File("./data/textfiles/1.txt")
// test1接收的参数类型为Rich,此时也自动进行了隐式转换
test1(f)
}
def test1(r:RichFile) = println(r.read())
}
隐式参数
函数或方法可以带有一个标记为implicit的参数列表。这种情况,编译器会查找缺省值,提供给该方法。
定义隐式参数:
在方法后面添加一个参数列表,参数使用implicit修饰
在object中定义implicit修饰的隐式值
调用方法,可以不传入implicit修饰的参数列表,编译器会自动查找缺省值
示例:
// 定义一个分隔符类
case class Delimiters(left:String, right:String)
object MyPredef1 {
implicit val quoteDelimiters = Delimiters("<<<", ">>>")
}
object ImplicitParamDemo {
// 使用分隔符将想要引用的字符串括起来
def quote(what:String)(implicit delims:Delimiters) = delims.left + what + delims.right
def main(args: Array[String]): Unit = {
println(quote("hello, world")(Delimiters("<<", ">>")))
// 手动导入
import MyPredef1._
println(quote("hello, world"))
}
}
和隐式转换一样,可以使用import手动导入隐式参数
如果在当前作用域定义了隐式值,会自动进行导入
以上是关于Scala隐式转换的主要内容,如果未能解决你的问题,请参考以下文章