名前による呼び出し:=>タイプ
=> Type
表記は、コール・バイ・名前の一つである、の略で多くの方法のパラメータが渡されます。それらに慣れていない場合は、今日のほとんどが値渡しと参照渡しであるにもかかわらず、ウィキペディアの記事を読むことをお勧めします。
つまり、渡されたものが関数内の値の名前に置き換えられます。たとえば、次の関数を使用します。
def f(x: => Int) = x * x
このように呼べば
var y = 0
f { y += 1; y }
次に、コードはこのように実行されます
{ y += 1; y } * { y += 1; y }
ただし、識別子名の競合が発生した場合に何が起こるかという点が浮上します。従来の名前による呼び出しでは、名前の競合を回避するために、キャプチャ回避置換と呼ばれるメカニズムが実行されます。ただし、Scalaでは、これは別の方法で実装され、同じ結果になります。パラメーター内の識別子名は、呼び出された関数の識別子を参照したり、シャドウしたりできません。
名前による呼び出しに関連する他のポイントがいくつかありますが、他の2つについては後で説明します。
0アリティ関数:()=>タイプ
構文() => Type
はのタイプを表しますFunction0
。つまり、パラメータをとらずに何かを返す関数です。これは、たとえば、メソッドを呼び出すことと同じsize()
です。パラメータをとらず、数値を返します。
しかし、興味深いのは、この構文が無名関数リテラルの構文と非常に似ていることです。これが混乱の原因です。例えば、
() => println("I'm an anonymous function")
アリティ0の無名関数リテラルで、型は
() => Unit
だから私たちは書くことができます:
val f: () => Unit = () => println("I'm an anonymous function")
ただし、タイプと値を混同しないようにすることが重要です。
ユニット=>タイプ
これは実際には単なるでありFunction1
、最初のパラメータは型Unit
です。それを書く他の方法は、(Unit) => Type
またはでしょうFunction1[Unit, Type]
。事は...これが人が望んでいるものである可能性は低いです。Unit
タイプの主な目的は、そうしても意味がありません、に興味を持っていない値の1を表示している受け取るその値を。
たとえば、
def f(x: Unit) = ...
何ができるx
でしょうか?値は1つだけなので、受け取る必要はありません。考えられる用途の1つは、次を返す関数のチェーンですUnit
。
val f = (x: Unit) => println("I'm f")
val g = (x: Unit) => println("I'm g")
val h = f andThen g
のでandThen
のみに定義されているFunction1
、と我々はチェーン化されている関数が戻ってきているUnit
、我々はタイプとしてそれらを定義しなければならなかったFunction1[Unit, Unit]
チェーンそれらのことができるようにします。
混乱の原因
混乱の最初の原因は、0アリティ関数に存在するタイプとリテラルの類似性が名前による呼び出しにも存在すると考えることです。言い換えれば、
() => { println("Hi!") }
のリテラルである() => Unit
場合、
{ println("Hi!") }
のリテラルになり=> Unit
ます。そうではない。これは、リテラルではなくコードのブロックです。
混乱のもう1つの原因は、Unit
型の値がに書き込まれることです()
。これは、アリティ0のパラメーターリストのように見えます(ただし、そうではありません)。
case class Scheduled(time: Int)(callback: => Unit)
です。セカンダリパラメータリストは公開されておらず、生成されたequals
/hashCode
メソッドにも含まれていないため、これは機能します。