scala中的传名调用

Posted 后端技术小黑屋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了scala中的传名调用相关的知识,希望对你有一定的参考价值。



scala函数调用的参数传递有两种方式:

  • 一种是传值调用,这种方式和C语言的函数参数传递方式类似,在函数调用的时刻,计算各个参数的值,然后传递进入函数内部,scala中写作function(x: Int);

  • 一种是传名调用,这种调用方式在函数调用时并不直接计算参数的具体值,而是在函数中使用到该参数时,才进行计算,scala中写作function(x: =>Int)。这里有意思的地方在于,在scala中, Int => Int表示一个函数类型,接受Int参数,返回Int返回值。那这里x的类型,就类似于一个函数,它没有参数,但是返回一个Int类型的返回值。

下面看一个并没有什么卵用,只为用于说明特性的例子:

package example

object TestThunk extends Greeting with App {
  def printAndReturnInt() = {
    println("test...")
    1       
  }
  callByValue(printAndReturnInt)
  callByName(printAndReturnInt)
}           

trait Greeting {
  def callByValue(x: Int) = {
    println("first call by value: x=" + x)
    println("second call by value: x=" + x)
  } 
  def callByName(x: => Int) = {
    println("first call by name: x=" + x)
    println("second call by name: x=" + x)
  } 
}

调用结果输出是:

test...
first call by value: x=1
second call by value: x=1
test...
first call by name: x=1
test...
second call by name: x=1

通过test…的输出,可以看出传名调用和传值调用的区别。


那这个传名调用,有什么作用呢?

首先,在部分情况下它可以提高效率:比如函数中没有用到这个传名调用参数的时候,这个参数就不会被计算。
但是,既然不会用到这个参数,你传它进函数干嘛?其实也是有这种情况的,比如熟悉的getOrElse,它的默认取值default就是一个传名调用:

def getOrElse[B >: A](default: ⇒ B): B  

另外,这种延迟参数计算到函数中实际调用位置的方式,也为scala的一些特性提供了支撑,比如Try:

Try的apply方法,接收的就是一个传名参数:

def apply[T](r: => T): Try[T] =
    try Success(r) catch {
      case NonFatal(e) => Failure(e)
    }

只有在构造Try时使用传名参数r,将r的调用推迟到Try内部,才能够在Try内部对异常进行处理;否则的话,r将在传入Try内部之前进行计算,在计算中出现的异常将会直接抛到Try外部,就不能实现Try对于异常的包装了,是不是很神奇很有用?



推荐阅读:





题图:GraphicMam-team

授权:CC0协议



以上是关于scala中的传名调用的主要内容,如果未能解决你的问题,请参考以下文章

Thunk函数的使用

Scala函数的调用

29.scala传名参数

Scala传名参数(By-Name)

ES6异步操作Thunkco和async

linux打开终端如何启动scala,如何在终端下运行Scala代码片段?