3

私は機能を持っています:

def nanoTime() = {
    println("Getting nano time...")
    System.nanoTime // returns nanoTime
}

関数を取る別の関数

def printTime(time: => Long) = {  // indicates a by-name parameter
    println(">> delayed()")
    println("Param: " + time)
    time // returns time
}

これが問題です。私がする時:

scala> printTime(nanoTime())
>> delayed()
Getting nano time...
Param: 546632085606127
Getting nano time...
res11: Long = 546632086131624

次の場合と同じ結果が得られます。

scala> printTime(nanoTime)
>> delayed()
Getting nano time...
Param: 546622367510997
Getting nano time...
res10: Long = 546622368149903

違いはありません:

scala> printTime(nanoTime())

scala> printTime(nanoTime)

したがって、関数名を渡すことと、関数名の後に () を付けて渡すことに違いはありません。これはいつものケースですか、それともこのケースの何が特別なのですか?

ありがとう。

4

1 に答える 1

8

Scala には、1 つのメソッドが複数のメソッドを取ることができるパラメーター リストの概念があります。ただし、便宜上、端末の空のパラメーター リストを省略できるようにもなっています。そう

f
f()
f()()

すべて同じものかもしれません - を見るまでわかりませんf。名前指定パラメーターの役割は、コード ブロックの実行を遅らせることです。さて、正式に

def f0: String = "salmon"
def f1(): String = "herring"
def f2()(): String = "halibut"

f0次に、関数に変換された場合、名前によるパラメーターと一致することを期待し、他のパラメーターは一致しないことを期待します。具体的には、

f0   <==>   => String
f1   <==>   () => String
f2   <==>   () => () => String

変換したとき。経由でリクエストしたときに実際に何が起こるか見てみましょうf _:

scala> f0 _
res4: () => String = <function0>

scala> f1 _
res5: () => String = <function0>

scala> f2 _
res6: () => () => String = <function0>

しかたがない; f0実際には、0 ではなく 1 つの空のパラメーター ブロックを持つ関数に変換されます (これは、名前によるパラメーターのように見えます)。したがって、名前によるパラメーターがメソッドを関数にまったく変換していないことがわかります-型シグネチャが一致しません!

代わりに、次のような理由があります。

// I need a code block that returns a long
nanoTime             // Wait, there is no nanoTime exactly
nanoTime()           // Aha, that works!  Must have meant that
: => { nanoTime() }  // There, nicely packaged.

違いが見られない理由は、 a を返すためLongに、 by-name パラメーターが欠落している をすでに埋めている()が、後で実行するためにすべてをコード ブロックにラップしているためです。

(また、名前によるパラメーターは実際には内部にあることに注意してください。つまりFunction0、実際にあり、「ゼロ パラメーター ブロック」は単なるコンパイラのフィクションです。実際には、すべてのパラメーター ブロックはコンパイラのフィクションです。つまり、JVM です。単一のパラメータ リストについてのみ知っている. そして、観察された動作をもたらすのは、このノーブロック フィクションと、空の括弧を気にするフィクションとの組み合わせです.)x: => Ax: () => A

空のパラメーター ブロックから関数を要求すると、次のように機能します。

def printF(f: () => String) = println(f())

scala> printF(f0)
<console>:23: error: type mismatch;
 found   : String
 required: () => String
              printF(f0)
                     ^

scala> printF(f1)
herring

scala> printF(f2)
<console>:23: error: type mismatch;
 found   : () => String
 required: String
              printF(f2)

scala> printF(f2())
halibut

コンパイラはメソッドのシグネチャを関数のシグネチャに一致させようとしているため、括弧が重要になります。名前によるパラメーター状況の特殊なケースは適用されなくなりました。

于 2013-01-20T22:33:02.507 に答える