继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

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

开心每一天1111
关注TA
已关注
手记 527
粉丝 49
获赞 218

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

 

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

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

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

原文出处:https://www.cnblogs.com/wangyalou/p/9574691.html

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP