scala成长之路(5)问题记录
2018-09-02 18:30
507 查看
还是在看scala sdk源码的时候,有很多问题要考自己慢慢摸索,这里做个记录。
一. 隐式转换的作用域?
隐式转换需要三个因素
1. 己方(当前对象)
2. 转换函数
3. 对方(转换的目标类)
这三个需要在同一个作用域内才能生效吗?举个简单的例子,依然是java HashSet隐式转换为scala Set(可以参看本系列(3)),我们只是在要用到转换的文件里写了一行:
也就是说导入了JavaConverters单例中的全部转换函数,但是我们并没有导入转换的目标类AsScala,所以按道理来说当前解释器并不知道AsScala的存在,就更不知道asScala方法要去哪寻找了。所以我们换一种思路,解释器的执行顺序也许是样:
1. 发现某个对象上调用了不存在的方法f
2. 以该对象为输入参数寻找所有的隐式转换函数
3. 列出所有隐式转换函数的输出参数类
4. 看看这些类中是否有方法f;如有,则执行转换;没有则报错。
因此我们可以回答所提出的问题了:并不需要三者在同一作用域内才能生效,只需要原对象、转换函数,就能触发隐式转换。
二. 隐式转换遇到继承类怎么办?
例如
输出:
from Person to Dog
wang, wang, wang...
可以看到,隐式转换会尽可能优先将原对象转换到子类。但是如果我们把上边的子类转换方法注释掉呢?
执行结果
子类无法转换,则转换为父类。所以我们可以总结得出,scala中的隐式转换有多个有继承目标类可选时,是自下而上的,从子类往父类去找。
三、传值参数与传名参数
形式:
注意传名参数的:和=之间一定要有空格!!!
在所传的参数为一个值(变量、常量)时,传名和传值并没有什么区别;只有当传递的为函数调用时,才会显现出差别:
传值参数将需要的参数调用计算完成之后,再将计算的结果作为一个单一的值输入函数运行(只算一次);
传名函数先将参数(需要执行的函数)传入函数体内,在需要用到该值的时候再执行(可能会算多次)。
看起来像是没什么区别是吧?请考虑这种情况,在某个类的方法中需要重复用到该参数,而该参数所传入的调用的函数每次返回的结果都不一样:
执行结果
二者之间的区别足够清晰且一目了然了吧~简单来说,
按值传递——劳动一次,享受一生
按名传递——每次都要自己动手
一. 隐式转换的作用域?
隐式转换需要三个因素
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 Dog
wang, 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
二者之间的区别足够清晰且一目了然了吧~简单来说,
按值传递——劳动一次,享受一生
按名传递——每次都要自己动手
相关文章推荐
- 一个Android应用开发菜鸟的成长之路——工作第一天:解决了java.lang.NoClassDefFoundError问题
- “flavor”与“buttonKnife"异常问题记录(小小码农在成长)
- 【软考之路】C部分问题记录
- 找一个地方记录我的技术成长之路
- 今,开通博客,记录自己的技术成长之路
- 一个菜鸟java码农的成长之路(3):ListIterator的使用及注意的问题
- 转载 -- IOS成长之路-关于iOS6.0 屏幕旋转的问题
- 【记录用】码农之路所遇到的问题
- STM32菜鸟成长记录---AD7792遇到的问题
- [Ubuntu笔记]我的Linux之路--常见问题记录(添加中)
- 新人博客,记录自己android的成长之路
- Spring-Cloud学习之路-问题记录
- linux下spark scala运行问题记录
- 开始用CSDN记录自己的学习之路,自己的成长之路!!!
- Matlab成长之路_5(解决out of memory问题)
- IOS成长之路-关于iOS6.0 屏幕旋转的问题
- Scala IDE for Eclipse 之spark scala语言开发环境搭建------遇到问题记录
- 记录一个IT菜鸟的成长之路。
- 手机游戏刷表流程记录—服务端菜鸟的成长之路
- [Debug之路]Linux+C遇到的问题记录