scala成长之路:问题记录

  scala成长之路(5)问题记录

  还是在看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 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())

  }

  执行结果

  按值传递打印五次时间:15358837613621535883761362153588376136215358837613621535883761362-------------------------按名传递打印五次时间:15358837680561535883769390153588377072315358837720571535883773391

  二者之间的区别足够清晰且一目了然了吧~简单来说,

  按值传递——劳动一次,享受一生

  按名传递——每次都要自己动手

猜你喜欢

转载自www.cnblogs.com/qfdsj/p/9579294.html
今日推荐