3

Scala のプレースホルダー構文に関連する小さな問題があります。だから私は数字の単純なリストを持っています:

myList = List(13, 24, 10, 35)

最初に、このリストを次のようにフィルタリングしようとしました

myList.filter(_ => (_ % 5) == 0)

コンパイラは、パラメータの型を推測できないため、不平を言います:

error: missing parameter type for expanded function ((x$2) => x$2.$percent(5))

わかりました、問題ありません: パラメータのタイプを追加しました

myList.filter(_:Int => _ % 5 == 0)

今、コンパイラは私にこれを与えます:

identifier expected but integer literal found.
       someNumbers.filter(_:Int => _ % 5 == 0)
                                       ^

なぜこの奇妙なエラーが発生するのか知っていますか? 私は本当にそれを理解していません...

前もって感謝します、

4

3 に答える 3

16

あなたにはわかりませんが、これは:

identifier expected but integer literal found.
       someNumbers.filter(_:Int => _ % 5 == 0)
                                       ^

すごいエラーです!まあ、人々がそれを望んでいるという意味ではありませんが、構文的に正しく、意図したものとはまったく異なるものを書くことができました。まず、有効なコードである書き換えを見てみましょう。

someNumbers.map(_: Int => _ <:< Any)

これで、それとあなたが書いたもの (エラー位置まで) との違いは 2 つだけであることがわかります:%に置き換えられ、<:(コンパイラが望んでいたように -- 数値ではなく識別子) に置き換えられました。5Any

上記のコードをコンパイルして実行すると、何かが返されるので、分解してみましょう。まず、次の 2 つのステートメントを検討してください。

someNumbers.map(_ + 1)
someNumber.map(_) // does not compile

それぞれの意味はわずかに異なり、次のように書き換えることができます。

someNumbers.map(x => x + 1)
x => someNumbers.map(x)

最初のものはコンパイルされます。これは、xパラメーターが宣言された時点で、コンパイラーが予想される型を認識しているためです。2 番目のものはコンパイルされません。これは、コンパイラが を参照した時点でx、それがどのように使用されるかがわからないためです。確かに、それはコンパイラがコードを書き直したからにすぎませんが、それがどうなるかです。

ここで重要なことは、 を追加したとき: Intに、コンパイラが 2 番目の方法で記述したものをコンパイルしようとし始めたことです。

あなたが書こうとしていたものは有効なコードではありません。例えば:

someNumbers.map(x => x + 1) // valid code
someNumbers.map((x: Int) => x + 1) // valid code
someNumbers.map(x : Int => x + 1) // "invalid" code

より正確に言うと、3 番目の例は「無効」です。なぜなら、コンパイラは型がどこで終了するかを認識していないからです! その理由を理解するには、次のステートメントを見てください。

val f: Int => Int = x => x

ここでは=>2 回登場しますが、毎回異なる意味を持ちます。最初のケース はInt => Int、 のシンタックス シュガーですFunction1[Int, Int]。つまり、=>inInt => Intは型の一部です。

2 番目のケースでは、x => x(大まかに) を表しnew Function1[Int,Int] { def apply(x: Int) = x }ます。この=>コードの は、無名関数の存在を示し、そのパラメーターを本体から分離します。

これで、コンパイラが をどのように解釈したかを理解できますsomeNumbers.filter(_: Int => _ % 5 == 0)。このような:

someNumbers.filter(_: Int => _ % 5 == 0) // gets rewritten as
(x: Int => _ % 5 == 0) => someNumbers.filter(x)

型とされていた意味Int => _ % 5 == 0=>が停止しない理由は既に確認しましたが、エラーが発生したのは5! こことあそこの間で何が起こっているのですか?

まず、コンパイル可能な例に戻ります。これは、あまりよく理解されておらず、あまり見られない Scala 構造を利用しています: 中置表記です。その例は、次のように書き直すことができます。

someNumbers.map(_: Int => _ <:< Any)
someNumbers.map(_: Int => <:<[_, Any])

つまり、の略のよう2 * 22.*(2)、のInt Map String略ですMap[Int, String]。これで、コンパイラ%_.

ただし、この時点では_、特に書き直された形式の の意味は不思議に見えるべきではありません。それは存在型です! より具体的には、ワイルドカードの存在タイプです。全体は次のように書き直すことができます。

(x: Function1[Int,<:<[t, Any] forSome { type t }]) => someNumbers.map(x)

または、シンタックス シュガーなしで (ただし、実装が若干異なります*):

new Function1[Function1[Int, <:<[t, Any] forSome { type t }], List[<:<[q, Any] forSome { type q }]] { 
  def apply(x) = someNumbers.map(x) 
}

さて、これはあなたが書きたかったものからほとんどかけ離れていることに同意しませんか? :-)

t(*) 実は、原文ではとは同じだと思いますqが、シンタックス シュガーなしで書き出す方法が思い浮かびませんでした。

于 2012-05-18T00:06:41.277 に答える
6

あなたはこれを意味しました:

val myList = List(13, 24, 10, 35)
myList.filter(x => (x % 5) == 0)

_のようなもののプレースホルダーはmyList.map(_ + 5)、関数を作成するための省略表現です。この場合はmyList.map(x => x + 5). つまり、「各項目を関数と 5の合計にmyList.map(_ => _ + 5)マップする」と言っているようなものだからです。myListx => x

このようなプレースホルダーの他の使用法は、パラメーターを無視することです。つまりmyList.map(_ => 1)、「アイテムを無視して、すべてを 5 にマップする」ということです。あなたの場合、アイテムをフィルタリングするかどうかを決定するためにアイテムが必要なので、持っ_ =>ていても意味がありません。

この式myList.filter(x => (x % 5) == 0)は、「 for each xin myList、保持する if (x % 5) == 0」を意味します。

于 2012-05-17T18:15:53.803 に答える
3

どうですか:

myList.filter(_ % 5 == 0)
于 2012-05-17T19:48:29.057 に答える