以下に、いくつかの機能を定義して試してみる小さなScalaセッションを示します。
scala> def test1(str: String) = str + str;
test1: (str: String)Java.lang.String
scala> test1("ab")
res0: Java.lang.String = abab
うまく動作します。
scala> val test2 = test1
<console>:6: error: missing arguments for method test1 in object $iw;
follow this method with `_' if you want to treat it as a partially applied function
val test2 = test1
^
おっとっと。
scala> val test2 = test1 _
test2: (String) => Java.lang.String = <function1>
scala> test2("ab")
res1: Java.lang.String = abab
うまくいく!
さて、折り畳むときに_
構文を見ました(_ + _
など)。私が理解しているように、_
は基本的に「引数」を意味します。 test1 _
は基本的にtest1
"に渡される引数を持つ関数を意味します。しかし、なぜexactlyがtest1
と同じではないのですか? _
を追加すると違いがありますか?
だから私は探索し続けました...
scala> val test3 = (str: String) => str + str
test3: (String) => Java.lang.String = <function1>
scala> test3("ab")
res2: Java.lang.String = abab
scala> val test4 = test3
test4: (String) => Java.lang.String = <function1>
ここでは_
なしで動作します! def
ed関数とval
ed関数の違いは何ですか?
Def'ed関数とval'ed関数の間に違いはありません。
scala> def test1 = (str: String) => str + str
test1: (String) => Java.lang.String
scala> val test2 = test1
test2: (String) => Java.lang.String = <function1>
scala> val test3 = (str: String) => str + str
test3: (String) => Java.lang.String = <function1>
scala> val test4 = test2
test4: (String) => Java.lang.String = <function1>
見る?これらはすべて関数であり、X => Y
タイプで示されます。
scala> def test5(str: String) = str + str
test5: (str: String)Java.lang.String
X => Y
タイプが表示されていますか?もしそうなら、眼科医に会いに行ってください。ここでの型は(X)Y
で、一般的にmethodを示すために使用されます。
実際、test1
、test2
、test3
、およびtest4
はすべて、関数を返すメソッドです。 test5
は、Java.lang.String
を返すメソッドです。また、test1
からtest4
はパラメーターを取りません(とにかくtest1
のみが取り得ました)、test5
は取ります。
したがって、違いは非常に簡単です。最初のケースでは、valにメソッドを割り当てようとしましたが、メソッドが取るパラメーターを入力しませんでした。したがって、末尾のアンダースコアを追加するまで失敗しました。つまり、私のメソッドを関数に変換するを意味していました。
2番目の例では関数があったので、他に何もする必要はありませんでした。
メソッドは関数ではなく、その逆も同様です。関数は、FunctionN
クラスのいずれかのオブジェクトです。メソッドは、オブジェクトに関連付けられたコードの一部へのハンドルです。
Stack Overflowのメソッドと関数に関するさまざまな質問をご覧ください。
def
は、Javaでメソッドを定義する方法と同様に、周囲のオブジェクト/クラス/トレイト内でメソッドを宣言します。 def
sは他のオブジェクト/クラス/トレイト内でのみ使用できます。 REPLでは、「隠されている」ため周囲のオブジェクトを見ることができませんが、実際には存在します。
def
は値ではないため、def
を値に割り当てることはできません。これはオブジェクトのメソッドです。
_(x: T) => x * x
_は、実行時に存在する関数オブジェクトを宣言およびインスタンス化します。関数オブジェクトは、FunctionN
特性を拡張する匿名クラスのインスタンスです。 FunctionN
トレイトには、apply
メソッドが付属しています。 apply
という名前は、省略できるため特別です。式f(x)
はf.apply(x)
に脱糖されます。
ボトムラインは-関数オブジェクトはヒープ上に存在するランタイム値であるため、値、変数、パラメーターに割り当てたり、メソッドから戻り値として返すことができます。
値にメソッドを割り当てる問題を解決するために(これは便利です)、Scalaを使用すると、プレースホルダー文字を使用してメソッドから関数オブジェクトを作成できます。式_test1 _
_上記の例は、メソッド_test1
_のラッパー関数を実際に作成します-x => test1(x)
と同等です。
アンダースコアは、異なるコンテキストで異なることを意味します。しかし、それは常にここに行くが、名前を付ける必要はないと考えることができます。
パラメーターの代わりに適用すると、メソッドを関数に持ち上げることになります。
scala> def test1(str: String) = str + str;
test1: (str: String)Java.lang.String
scala> val f1 = test1 _
f1: (String) => Java.lang.String = <function1>
このメソッドは、タイプ(String)=> Stringの関数になっていることに注意してください。
Scalaのメソッドと関数の違いは、メソッドが従来のJavaメソッドに似ていることです。値として渡すことはできません。ただし、関数それ自体が値であり、入力パラメーターおよび戻り値として使用できます。
さらに持ち上げることができます:
scala> val f2 = f1 _
f2: () => (String) => Java.lang.String = <function0>
この機能を解除すると、別の機能が発生します。今回はタイプ()=>(String)=>(String)
私の知る限り、この構文はすべてのパラメーターを明示的にアンダースコアに置き換えることと同等です。例えば:
scala> def add(i: Int, j: Int) = i + j
add: (i: Int,j: Int)Int
scala> val addF = add(_, _)
addF: (Int, Int) => Int = <function2>
scala> val addF2 = add _
addF2: (Int, Int) => Int = <function2>