あなたにはわかりませんが、これは:
identifier expected but integer literal found.
someNumbers.filter(_:Int => _ % 5 == 0)
^
すごいエラーです!まあ、人々がそれを望んでいるという意味ではありませんが、構文的に正しく、意図したものとはまったく異なるものを書くことができました。まず、有効なコードである書き換えを見てみましょう。
someNumbers.map(_: Int => _ <:< Any)
これで、それとあなたが書いたもの (エラー位置まで) との違いは 2 つだけであることがわかります:%
に置き換えられ、<:
(コンパイラが望んでいたように -- 数値ではなく識別子) に置き換えられました。5
Any
上記のコードをコンパイルして実行すると、何かが返されるので、分解してみましょう。まず、次の 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 * 2
に2.*(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
が、シンタックス シュガーなしで書き出す方法が思い浮かびませんでした。