在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ Scala/ 傳名參數(shù)
包對象
Ordered Trait
組合和繼承–定義 final 成員
基本數(shù)據(jù)類型
Match 表達式
類和對象 (三)
操作基本數(shù)據(jù)類型
for 表達式
組合和繼承–重載成員函數(shù)和方法
類和對象 (二)
組合和繼承–定義 factory 對象
組合和繼承–多態(tài)和動態(tài)綁定
Trait 的基本概念
if 表達式
組合和繼承–抽象類
函數(shù)–函數(shù)字面量的一些簡化寫法
while 循環(huán)
組合和繼承–使用組合還是繼承?
訪問控制修飾符
Trait 示例–Rectangular 對象
組合和繼承–定義參數(shù)化成員變量
組合和繼承–定義無參數(shù)方法
類和對象 (一)
函數(shù)–閉包
函數(shù)–類成員函數(shù)
Scala 基本數(shù)據(jù)類型的實現(xiàn)方法
try 表達式處理異常
選擇瘦接口還是胖接口設(shè)計?
組合和繼承–小結(jié)
創(chuàng)建新的控制結(jié)構(gòu)
使用 import
為訪問控制修飾符添加作用域
Scala 的類層次關(guān)系
類和對象 (五)
傳名參數(shù)
柯里化函數(shù)
函數(shù)–頭等公民
組合和組合和繼承–定義 heighten 和 widen 函數(shù)
使用 Package–將代碼放入包中
隱含的 import
所有類的公共子類–底層類型
進一步 Scala
函數(shù)–局部函數(shù)
引用包中的代碼
組合和繼承–使用 override 修飾符
組合和繼承–實現(xiàn)類 Element 的 above,beside 和 toString()方法
類和對象 (四)
函數(shù)–尾遞歸
沒有“break”和“continue”的日子
組合和繼承–調(diào)用基類構(gòu)造函數(shù)
減低代碼重復(fù)
函數(shù)–函數(shù)–可變參數(shù),命名參數(shù),缺省參數(shù)
起步 Scala
組合和繼承–擴展類
函數(shù)–部分應(yīng)用的函數(shù)
開始神奇的 Scala編程之旅
組合和繼承–概述
Trait 用來實現(xiàn)可疊加的修改操作

傳名參數(shù)

上篇我們使用柯里化函數(shù)定義一個控制機構(gòu) withPrintWriter,它使用時語法調(diào)用有如 Scala 內(nèi)置的控制結(jié)構(gòu):

val file = new File("date.txt")
withPrintWriter(file){
  writer => writer.println(new java.util.Date)
}

不過仔細看一看這段代碼,它和 scala 內(nèi)置的 if 或 while 表達式還是有些區(qū)別的,withPrintWrite r的{}中的函數(shù)是帶參數(shù)的含有“writer=>”。 如果你想讓它完全和 if 和 while 的語法一致,在 Scala 中可以使用傳民參數(shù)來解決這個問題。

:我們知道通常函數(shù)參數(shù)傳遞的兩種模式,一是傳值,一是引用。而這里是第三種按名稱傳遞。

下面我們以一個具體的例子來說明傳名參數(shù)的用法:

var assertionsEnabled=true
def myAssert(predicate: () => Boolean ) =
  if(assertionsEnabled && !predicate())
    throw new AssertionError

這個 myAssert 函數(shù)的參數(shù)為一個函數(shù)類型,如果標志 assertionsEnabled 為 True 時,mymyAssert 根據(jù) predicate 的真假決定是否拋出異常,如果 assertionsEnabled 為 false,則這個函數(shù)什么也不做。

這個定義沒什么問題,但調(diào)用起來看起來卻有些別扭,比如:

myAssert(() => 5 >3 )

還需要 ()=>,你可以希望直接使用 5>3,但此時會報錯:

scala> myAssert(5 >3 )
<console>:10: error: type mismatch;
 found   : Boolean(true)
 required: () => Boolean
              myAssert(5 >3 )

此時,我們可以把按值傳遞(上面使用的是按值傳遞,傳遞的是函數(shù)類型的值)參數(shù)修改為按名稱傳遞的參數(shù),修改方法,是使用=>開始而不是 ()=>來定義函數(shù)類型,如下:

def myNameAssert(predicate:  => Boolean ) =
  if(assertionsEnabled && !predicate)
    throw new AssertionError

此時你就可以直接使用下面的語法來調(diào)用 myNameAssert:

myNameAssert(5>3)

此時就和 Scala 內(nèi)置控制結(jié)構(gòu)一樣了,看到這里,你可能會想我為什么不直接把參數(shù)類型定義為 Boolean,比如:

def boolAssert(predicate: Boolean ) =
  if(assertionsEnabled && !predicate)
    throw new AssertionError

調(diào)用也可以使用

boolAssert(5>3)

和 myNameAssert 調(diào)用看起來也沒什么區(qū)別,其實兩者有著本質(zhì)的區(qū)別,一個是傳值參數(shù),一個是傳名參數(shù),在調(diào)用 boolAssert(5>3)時,5>3 是已經(jīng)計算出為 true,然后傳遞給 boolAssert 方法,而 myNameAssert(5>3),表達式 5>3 沒有事先計算好傳遞給 myNameAssert,而是先創(chuàng)建一個函數(shù)類型的參數(shù)值,這個函數(shù)的 apply 方法將計算5>3,然后這個函數(shù)類型的值作為參數(shù)傳給 myNameAssert。

因此這兩個函數(shù)一個明顯的區(qū)別是,如果設(shè)置 assertionsEnabled 為 false,然后試圖計算 x/0 ==0,

scala> assertionsEnabled=false
assertionsEnabled: Boolean = false
scala> val x = 5
x: Int = 5
scala> boolAssert ( x /0 ==0)
java.lang.ArithmeticException: / by zero
  ... 32 elided
scala> myNameAssert ( x / 0 ==0)

可以看到 boolAssert 拋出 java.lang.ArithmeticException: / by zero 異常,這是因為這是個傳值參數(shù),首先計算 x /0 ,而拋出異常,而 myNameAssert 沒有任何顯示,這是因為這是個傳名參數(shù),傳入的是一個函數(shù)類型的值,不會先計算 x /0 ==0,而在 myNameAssert 函數(shù)體內(nèi),由于 assertionsEnabled 為 false,傳入的 predicate 沒有必要計算(短路計算),因此什么也不會打印。如果我們把 myNameAssert 修改下,把 predicate 放在前面:

scala> def myNameAssert1(predicate:  => Boolean ) =
     |   if( !predicate && assertionsEnabled )
     |     throw new AssertionError
myNameAssert1: (predicate: => Boolean)Unit
scala> myNameAssert1 ( x/0 ==0)
java.lang.ArithmeticException: / by zero
  at $anonfun$1.apply$mcZ$sp(<console>:11)
  at .myNameAssert1(<console>:9)
  ... 32 elided

這個傳名參數(shù)函數(shù)也拋出異常(你可以想想是為什么?)

前面的 withPrintWriter 我們暫時沒法使用傳名參數(shù),去掉 writer=>,否則就難以實現(xiàn)“租賃模式”,不過我們可以看看下面的例子,設(shè)計一個 withHelloWorld 控制結(jié)構(gòu),這個 withHelloWorld 總打印一個“hello,world”

import scala.io._
import java.io._
def withHelloWorld ( op: => Unit) {
  op   
  println("Hello,world")
}
val file = new File("date.txt")
withHelloWorld{
  val writer=new PrintWriter(file)
  try{
   writer.println(new java.util.Date)
  }finally{
    writer.close()
  }
}
withHelloWorld {
  println ("Hello,Guidebee")
} 

Hello,world 
Hello,Guidebee
Hello,world

可以看到 withHelloWorld 的調(diào)用語法和 Scala 內(nèi)置控制結(jié)構(gòu)非常象了。