44

これは、いくつかの関数を定義して試す小さな 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ます。しかし、それが単にとまったく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>

ここでは、なしで動作し_ます! defed 関数と ed 関数の違いは何valですか?

4

3 に答える 3

58

def、Java でメソッドを定義する方法と同様に、周囲のオブジェクト/クラス/特性内でメソッドを宣言します。defs は、他のオブジェクト/クラス/特性内でのみ使用できます。REPL では、周囲のオブジェクトは「隠されている」ため見えませんが、存在します。

は値ではなく、オブジェクト内のメソッドであるdefため、値に を割り当てることはできません。def

は、実行時に存在する関数オブジェクト(x: T) => x * xを宣言してインスタンス化します。関数オブジェクトは、特性を拡張する無名クラスのインスタンスです。トレイトにはメソッドが付属しています。名前は省略できるため、特別です。式は に脱糖されます。FunctionNFunctionNapplyapplyf(x)f.apply(x)

肝心なのは、関数オブジェクトはヒープ上に存在するランタイム値であるため、それらを値、変数、およびパラメーターに割り当てるか、メソッドから戻り値として返すことができるということです。

メソッドを値に代入する問題 (これは便利です) を解決するために、Scala ではプレースホルダー文字を使用してメソッドから関数オブジェクトを作成できます。上記の例の式test1 _は、実際にはメソッドの周りにラッパー関数を作成します。test1これは と同等x => test1(x)です。

于 2011-02-15T21:13:18.117 に答える
53

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を表すために一般的に使用されるです。

実際にtest1test2、、、test3およびtest4はすべてメソッドであり、関数を返します。test5を返すメソッドjava.lang.Stringです。また、test1throughtest4はパラメータを取得しません(test1とにかく可能でした)が、取得しますtest5

したがって、違いは非常に単純です。最初のケースでは、メソッドをvalに割り当てようとしましたが、メソッドが取るパラメーターを入力しませんでした。したがって、末尾にアンダースコアを追加するまで失敗しました。これは、メソッドを関数に変換することを意味します。

2番目の例では、関数があったので、他に何もする必要はありませんでした。

メソッドは関数ではなく、その逆も同様です。関数は、FunctionNクラスの1つのオブジェクトです。メソッドは、オブジェクトに関連付けられたコードの一部へのハンドルです。

StackOverflowのメソッドと関数に関するさまざまな質問をご覧ください。

于 2011-02-16T01:03:58.760 に答える
11

アンダースコアは、さまざまなコンテキストでさまざまなことを意味します。しかし、それは常にここにあるものと考えることができますが、名前を付ける必要はありません

パラメーターの代わりに適用すると、その効果はメソッドを関数に持ち上げることです。

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>

この関数を持ち上げると、別の関数になります。今回は () => (文字列) => (文字列) 型の

私が知る限り、この構文は、すべてのパラメーターを明示的にアンダースコアに置き換えることと同等です。例えば:

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>
于 2011-02-15T23:00:48.547 に答える