Scala基礎 - 傳名參數和傳值參數(by-name/by-value parameter)

1. 介紹

傳值參數在函數調用以前表達式會被求值,例如Int,Long等數值參數類型;傳名參數在函數調用前表達式不會被求值,而是會被包裹成一個匿名函數做爲函數參數傳遞下去,例如參數類型爲無參函數的參數就是傳名參數。下文將舉例說明這二者的區別。express

2. 簡單類型的傳遞示例

2.1 傳值參數(by-value parameter)示例

在下面的示例中,編譯器檢測到strToInt接受一個傳值參數,因此先對傳入的參數表達式{println("eval parameter expression"); "123"},而後再講求值結果傳遞給strToInt。函數

object Test {
  def strToInt(s: String) = {
    println("call strToInt")
    s.toInt
  }

  def main(args: Array[String]) {
    strToInt({println("eval parameter expression"); "123"})
  }
}
//輸出:
eval parameter expression
call strToInt

2.2. 傳名參數(by-name parameter)示例

strToInt函數聲明中添加一個=>,參數s的類型就變成了無參函數,類型爲:() => String,按照Scala針對無參函數的簡化規則,此處省略了()。由於參數s的類型是無參函數,因此此處是按名傳遞。code

object Test {
  def strToInt(s: => String) = {
    println("call strToInt")
    s.toInt
  }

  def main(args: Array[String]) {
    strToInt({println("eval parameter expression"); "123"})
  }
}
//輸出:
call strToInt
eval parameter expression

從上面的輸出能夠看出,參數表達式在strToInt函數調用以後才被求值。其實此處編譯器自動將參數表達式{println("eval parameter expression"); "123"}轉換成匿名的無參函數,並傳遞給s編譯器

3. 複雜類型的傳遞示例

3.1 傳值參數(by-value parameter)示例

invode函數的參數f的類型爲柯里化函數String => Int => Long, 此處爲按值傳遞。io

object Test {
  def invode(f: String => Int => Long) = {
    println("call invoke")
    f("1")(2)
  }

  def curry(s: String)(i: Int): Long = {
    s.toLong + i.toLong
  }

  def main(args: Array[String]) {
    invode{println("eval parameter expression");curry}
  }
}
//輸出:
eval parameter expression
call invoke

3.2 傳名參數(by-name parameter)示例

invode函數的參數f的類型爲一個無參函數,該無參函數的返回類型爲柯里化函數String => Int => Long, 由於參數f的類型是無參函數,因此此處是按名傳遞。編譯

object Test {
  def invode(f: => String => Int => Long) = {
    println("call invoke")
    f("1")(2)
  }

  def curry(s: String)(i: Int): Long = {
    s.toLong + i.toLong
  }

  def main(args: Array[String]) {
    invode{println("eval parameter expression");curry}
  }
}
//輸出:
call invoke
eval parameter expression

4. 小結

若是參數類型是無參函數,則按名傳遞,不然按值傳遞。注意,若是參數類型是函數類型,但不是無參函數,仍是按值傳遞,例如:匿名函數

object Test {
  def strToInt(s: (String) => Int) = {
    println("call strToInt")
    s("123")
  }

  def main(args: Array[String]) {
    strToInt({println("eval parameter expression"); (s: String) => s.toInt})
  }
}
//輸出:
eval parameter expression
call strToInt
相關文章
相關標籤/搜索