还是在看 scala sdk 源码的时候, 有很多问题要考自己慢慢摸索, 这里做个记录.
一. 隐式转换的作用域?
隐式转换需要三个因素
1. 己方(当前对象)
2. 转换函数
3. 对方(转换的目标类)
这三个需要在同一个作用域内才能生效吗? 举个简单的例子, 依然是 java HashSet 隐式转换为 scala Set(可以参看本系列(3)), 我们只是在要用到转换的文件里写了一行:
import scala.collection.JavaConverters._
也就是说导入了 JavaConverters 单例中的全部转换函数, 但是我们并没有导入转换的目标类 AsScala, 所以按道理来说当前解释器并不知道 AsScala 的存在, 就更不知道 asScala 方法要去哪寻找了. 所以我们换一种思路, 解释器的执行顺序也许是样:
1. 发现某个对象上调用了不存在的方法 f
2. 以该对象为输入参数寻找所有的隐式转换函数
3. 列出所有隐式转换函数的输出参数类
4. 看看这些类中是否有方法 f; 如有, 则执行转换; 没有则报错.
因此我们可以回答所提出的问题了: 并不需要三者在同一作用域内才能生效, 只需要原对象, 转换函数, 就能触发隐式转换.
二. 隐式转换遇到继承类怎么办?
例如
- class SmartAnimal (n:String){
- val name = n
- }
- class Person (n:String) extends SmartAnimal(n) {
- override val name = n
- }
- object converter {
- implicit def asDog(person: Person):Dog = {
- print("from Person to Dog")
- new Dog(person.name + "_dog")
- }
- implicit def asDog(animal:SmartAnimal):Dog = {
- print("from SmartAnimal to Dog")
- new Dog(animal.name)
- }
- }
- def main(args: Array[String]) = {
- var a = new Person("aaa")
- a.bark
- }
输出:
from Person to Dogwang, wang, wang...
可以看到, 隐式转换会尽可能优先将原对象转换到子类. 但是如果我们把上边的子类转换方法注释掉呢?
- object converter {
- // implicit def asDog(person: Person):Dog = {
- // print("from Person to Dog\n")
- // new Dog(person.name + "_dog")
- // }
- implicit def asDog(animal:SmartAnimal):Dog = {
- print("from SmartAnimal to Dog\n")
- new Dog(animal.name)
- }
- }
执行结果
- from SmartAnimal to Dog
- wang, wang, wang...
子类无法转换, 则转换为父类. 所以我们可以总结得出, scala 中的隐式转换有多个有继承目标类可选时, 是自下而上的, 从子类往父类去找.
三, 传值参数与传名参数
形式:
- def funByName(arg: =>Int) = println(arg)// 传名参数
- def funByValue(arg:Int) = println(arg)// 传值参数
注意传名参数的: 和 = 之间一定要有空格!!!
在所传的参数为一个值 (变量, 常量) 时, 传名和传值并没有什么区别; 只有当传递的为函数调用时, 才会显现出差别:
传值参数将需要的参数调用计算完成之后, 再将计算的结果作为一个单一的值输入函数运行(只算一次);
传名函数先将参数 (需要执行的函数) 传入函数体内, 在需要用到该值的时候再执行(可能会算多次).
看起来像是没什么区别是吧? 请考虑这种情况, 在某个类的方法中需要重复用到该参数, 而该参数所传入的调用的函数每次返回的结果都不一样:
- def pTimeByValue(time:Long) = {
- for(i <- 1 to 5){
- println(time)
- Thread.sleep(1333)
- }
- }
- def pTimeByName(time: =>Long) = {
- for(i <- 1 to 5){
- println(time)
- Thread.sleep(1333)
- }
- }
- def main(args: Array[String]) = {
- println("按值传递打印五次时间:")
- pTimeByValue(System.currentTimeMillis())
- println("-------------------------\n 按名传递打印五次时间:")
- pTimeByName(System.currentTimeMillis())
- }
执行结果
按值传递打印五次时间:
- 1535883761362
- 1535883761362
- 1535883761362
- 1535883761362
- 1535883761362
- -------------------------
按名传递打印五次时间:
- 1535883768056
- 1535883769390
- 1535883770723
- 1535883772057
- 1535883773391
二者之间的区别足够清晰且一目了然了吧~ 简单来说,
按值传递 -- 劳动一次, 享受一生
按名传递 -- 每次都要自己动手
来源: https://www.cnblogs.com/wangyalou/p/9574691.html