Scala的解釋器在解析函數參數(function arguments)時有兩種方式:先計算參數表達式的值(reduce the arguments),再應用到函數內部;或者是將未計算的參數表達式直接應用到函數內部。前者叫做傳值調用(call-by-value),后者叫做傳名調用(call-by-name)。
傳值函數和傳名函數
object Add { def addByName(a: Int, b: => Int) = a + b def addByValue(a: Int, b: Int) = a + b }
傳名函數和傳值函數在編譯器中區別:
addByName(2, 2 + 2) ->2 + (2 + 2) ->2 + 4 ->6 addByValue(2, 2 + 2) ->addByValue(2, 4) ->2 + 4 ->6
可以看出,在進入函數內部前,傳值調用方式就已經將參數表達式的值計算完畢,而傳名調用是在函數內部進行參數表達式的值計算的。
這就造成了一種現象,每次使用傳名調用時,解釋器都會計算一次表達式的值。對於有副作用(side-effect)的參數來說,這無疑造成了兩種調用方式結果的不同。
因此, 在實際的使用中:
傳值調用在進入函數體之前就對參數表達式進行了計算,這避免了函數內部多次使用參數時重復計算其值,在一定程度上提高了效率。
但是傳名調用的一個優勢在於,如果參數在函數體內部沒有被使用到,那么它就不用計算參數表達式的值了。在這種情況下,傳名調用的效率會高一點。
package com.doggie object WhyAlwaysMe { var flag: Boolean = true def useOrNotUse(x: Int, y: => Int) = { flag match{ case true => x case false => x + y } } def main(args: Array[String]) = { println(useOrNotUse(1, 2)) flag = false println(useOrNotUse(1, 2))
=> Unit 與 () =>Unit的區別
簡單來說, => Unit是 傳名函數, 只傳入了一個表達式, 在調用時才會去執行, 使用 code調用
() => 是傳值函數, 傳入的計算后的值, 使用 code() 調用
package main.scala /** * Created by wenbronk on 2017/9/12. */ object TestScala { def main(args: Array[String]): Unit = { // println( addInt(3, 5)) // println(time()) delayTime({ println("2222"); time() }) delayTime2({ println("333"); time }) } def delayTime2(t: () => Long): Unit = { println("執行...") println( t() ) println("jiesu..") } def delayTime(t: => Long): Unit = { println("執行開始") println(t) println("執行結束") } def time() = { println("獲取時間內, 單位為 納秒") System.nanoTime() } }
執行結果:
http://blog.csdn.net/asongoficeandfire/article/details/21889375
http://www.aboutyun.com/thread-10864-1-3.html
http://scalagroup.group.iteye.com/group/topic/26303