2

次のコード スニペットを理解できませんでしafterDelay(0) {...}た。ローカルで定義された関数をアジェンダに保存できるのはなぜですか? afterDelay(0) {...}関数内の を理解するのを手伝ってくれる人はいrunますか?

abstract class Simulation {

  type Action = () => Unit

  case class WorkItem(time: Int, action: Action)

  private var curtime = 0
  def currentTime: Int = curtime

  private var agenda: List[WorkItem] = List()

  private def insert(ag: List[WorkItem], item: WorkItem): List[WorkItem] = {
    if (ag.isEmpty || item.time < ag.head.time) item :: ag
    else ag.head :: insert(ag.tail, item)
  }

  def afterDelay(delay: Int)(block: => Unit) {
    val item = WorkItem(currentTime + delay, () => block)
    agenda = insert(agenda, item)
  }

  private def next() {
    (agenda: @unchecked) match {
      case item :: rest => 
        agenda = rest 
        curtime = item.time
        item.action()
    }
  }

  def run() {
    afterDelay(0) {
      println("*** simulation started, time = "+
          currentTime +" ***")
    }
    while (!agenda.isEmpty) next()
  }
}
4

2 に答える 2

3
afterDelay(0) {
    println(...)
}

以下と同等です。

afterDelay(0)({
    println(...)
})

関数afterDelayが呼び出され、関数自体ではなく、新しいWorkItem( ) がリストに追加されます。itemパラメーターblock: => Unitは「名前によるパラメーター」です( Scala 言語仕様のセクション 4.6.1 を参照)。引数として使用される式は、変数が呼び出されるたびに呼び出される「パラメーターなしのメソッド」に (最初に評価されることなく) 暗黙的に変換されます。メソッド内にアクセスします (()不要)。

この場合、それは次の結果の関数() => block呼び出されたときです。これは、 newがリストに追加された(そして戻った)item.action()のある時点で呼び出されます。WorkItemafterDelay

次のように記述されている場合 (名前/サンクではなく、関数パラメーターを取り込む):

def afterDelay(delay: Int)(block: () => Unit) {   // take a function
  // new function will invoke function named by "block" when invoked ...
  val item = WorkItem(..., () => block())
  // or skip wrapping the function in a function ...
  // val item = WorkItem(..., block)
  ...
}

次に、関数を渡して呼び出す必要があります。

afterDelay(0)(() => { // need a function
    println(...)
})

または、代替構文、まだ の関数です() => Unitが、外側の括弧は避けることができます:

afterDelay(0) { () => // need a function
    println(...)
} 

SLS、4.6.1 By-Name パラメーターからの抜粋:

=>値パラメータのタイプには、接頭辞が付いている場合がありますx: => T。このようなパラメーターの型は、パラメーターなしのメソッド type=> Tです。これは、対応する引数が関数適用の時点では評価されず関数内で使用されるたびに評価されることを示します。つまり、引数は名前による呼び出しを使用して評価されます。

于 2012-05-08T04:33:08.470 に答える
1

afterDelay をカリー化された関数として定義しました。これは、2 つのパラメーター リストがあることを意味します。scala では、パラメータ リスト(...)を囲む括弧を に置き換えることができます{...}。2 番目のパラメーター リストでは、「名前による呼び出し」パラメーターを使用しています。これらのパラメーターは、関数で再度使用するたびに評価されます。良い例はここにあります。
「名前による呼び出し」パラメーターは、独自の制御構造を定義するためによく使用されます。

def do(until: Int)(body: => Unit) {
  body
  if (until > 1) do(until - 1)(body)
}

do(0)(println("test"))
do(5)(println("test2"))

これは do until の例です。test1 回と 5 回印刷されますtest2

于 2012-05-08T07:09:49.213 に答える