3

私は他の誰かのJavaコードをscalaに変換しています(好奇心が強いので、これはここの例です)、そして私は以下のコンパイラエラーに遭遇しました(いくらか単純化されています):

var out = new Formatter(new StringBuilder(), Locale.US)
out.format("%s-%d ", someObject, someInteger);

そして、これが私が受け取るエラーメッセージです:

[error]   (java.util.Locale,java.lang.String,<repeated...>
[java.lang.Object])java.util.Formatter <and>
[error]   (java.lang.String,<repeated...>[java.lang.Object])java.util.Formatter
[error]  cannot be applied to (java.lang.String, java.lang.Object, Int)
...
[error] one error found

これは、2行目を次のように変更した場合に機能します。

out.format("%s-%d ", someObject, someInteger.asInstanceOf[Object]);

誰かがこれがなぜであるか説明できますか?

これは、オブジェクト引数が期待されているが、scalaではそうではない整数をJavaで渡しても問題がないことを意味しますか?

4

4 に答える 4

4

他の答えはすべて何かを追加しますが、問題が何であるかを説明しているかどうかはわかりません。

それはすべて、JavaのプリミティブであるのIntに対し、Scalaのクラスであることに帰着します。intしたがって、Javaでは、メソッドがを期待することを記述し、Objectを渡すとint、Javaはそれを。に自動ボックス化しますjava.lang.Integer

java.lang.Object現在、 ScalaでのJavaの同等物はですAnyRefが、のサブクラスでIntはありませんAnyRef。そのための適切なタイプがあります:Any。には、Javaのプリミティブであるものと、サブクラスであるもののAny両方を含めることができます。メソッドがを期待して渡すjava.lang.Objectと言う場合、それは自動ボックス化されますが、はそうではありません。AnyIntAnyRef

したがって、Javaとインターフェースを取り、メソッドがボックス化されたプリミティブを渡すことを期待する場合は常に、ボックス化を自分で強制する必要があります。Scalaで期待するメソッドを作成し、AnyそれをキャストしてAnyRefJavaに相当するものを呼び出すと、そのメソッドを頻繁に呼び出す場合に簡単になります。

于 2012-08-20T14:31:03.653 に答える
2

定義方法を指定しませんsomeIntegerが、次のようなことをしようとしていると思います。

val someObject: Object = "this"
val someInteger = 3

var out = new Formatter(new StringBuilder(), Locale.US)
out.format("%s-%d ", someObject, someInteger);

someInteger = 3問題は、Scalaで言うと、変数はIntJavaではなくScalaintであり、JavaFormatterはそれをどう処理するかを知らないということです。

Javaが理解できる整数型を使用するように宣言を変更すると、問題なく機能します。例えば:

import java.lang.Integer

val someInteger = new Integer(3)

なぜ醜いasInstanceOfバージョンが機能するのですか?REPLを簡単にチェックすると、何が起こっているかがわかります。

scala> 3.asInstanceOf[java.lang.Object].getClass
res0: java.lang.Class[_ <: java.lang.Object] = class java.lang.Integer

したがって、を呼び出す.asInstanceOf[java.lang.Object]Int、Scalaはあなたにを返しますjava.lang.Integer

しかし実際には、もっとScala風の方法でコードを書き直す必要があります。アンドリュー・マッカラムはあなたがそうしたらもっと幸せになるでしょう。

于 2012-08-20T06:29:36.940 に答える
2

クラス階層は、javaとscalaで同じではありません。 java.lang.ObjectJavaの階層のルートにあります。Scalaでは、Anyタイプはルートにあります。したがって、タイプがパラメータをとる関数には何でも渡すことができますAny。ただし、タイプのjava.lang.Objectパラメーターを受け取る関数に渡すことができるのは、のサブタイプのみjava.lang.Objectです。

さらに悪いことに、整数には2つのタイプがあります。ScalaのInt型とjava.lang.Integerがあります。前者は、scalaで何かをリテラルの数値に設定したときに通常得られるものです。後者は、new Integer(3)またはで得られるものです3.asInstanceOf[Integer]。scala Intはjava.lang.Objectを継承しませんが、java.lang.Integerは継承します。その結果、java.lang.Objectを期待するパラメーターとしてscalaIntを渡すことはできません。これがscalaでは機能しない理由です。

Javaの話は少し奇妙です。以前は、オブジェクトが期待されていた場所にJavaをint渡すことができませんでした。それらを明示的にに変換する必要がありましたjava.lang.Integer。ただし、最近の変更(バージョン5)では、これが自動的に行われます。これは、変換がどちらの方向に進んでいるかに応じて、オートボクシングまたはアンボクシングと呼ばれます。そのため、Javaで機能します。

于 2012-08-20T06:43:05.750 に答える
1

dhgが言ったように、scalaコンパイラーはScalaint型をJavaint型とは異なるものとして扱います。JavaConversions暗黙のインポートを試して、それが役立つかどうかを確認できます。正確な違いはよくわかりません(同じように扱われると思います)。

または、Scalaフォーマットツールを使用することもできます。

val someObject: Object = "this"
val someInteger = 3
val out = "%s-%d ".format(someObject, someInteger)
于 2012-08-20T06:40:58.447 に答える