2017-10-05 16 views
0

これが私たちのアプリケーションで何が起こっているかの単純化されたコードです.Stringをjava.lang.Booleanにキャストすることはできませんクラスキャスト例外(「==」オーバーライド)

私は何か間違っていることを理解していますが、わかりません。

class First { def ==(first:First)= true} 

、今REPLに誤りがある:

error: type mismatch; 
found : First(in object $iw) 
required: First(in object $iw) 
     Second(new First) == Second(new First) 

さらに予想外の私には:

\私は変更することで、コードを変更した

EDIT

UPDATE 2番目の例は私のせいです。 REPLのクラスFirstを対話的に変更して、奇妙な結果を引き起こしました。最初から始めるそれは動作します。それでも...最初の1つ...

答えて

1

Secondはケースクラスであり、それはカスタムequalsメソッドを定義したり、継承していないので、Second#equalsのために生成されたコードは、あなたの==(First)、ではないでしょう

override def equals(x: Any): Boolean = x match { 
    case x: Second => first == x.first 
    case _ => false 
} 

最初の分岐で==のようになります。通常は==(Any)です。より具体的なオーバーロードであるためです。したがって、Secondを宣言するときにコンパイルエラーが発生するはずです。

しかし、スタックトレースからは、代わりに(x match ...).asInstanceOf[Boolean]または(first == x.first).asInstanceOf[Boolean]のいずれかのキャストが挿入されているようです。正直言って、このように書かれた理由を本当に考えることはできません。しかし、これによりSecondがコンパイルされ、後で呼び出しが失敗します。

+1

この説明は水を保持しているようには見えません。コンパイラーは実際にはオーバーロードされたメソッドを呼び出すときに、戻り値の型を考慮に入れるほどスマートです。私がこれをするとき、 'class Foo {def bar(x:Any):Boolean = false; (foo:)。bar( "baz") 'が正しく動作し、' false'を返します。 – Dima

+0

@Dima私がhttp://www.scala-lang.org/files/archive/spec/2.12/06-expressions.html#overloading-resolutionを正しく読んでいるのであれば、それは正しく動作しません。両方代替は適用可能であり(パラメータ型のみに依存する)、戻り型の型は多型の場合のみ重要です。もちろん、ルールはかなり複雑なので、何かが欠けているかもしれません。 –

+0

@Dimaまた、コンパイラはキャストを挿入するので(そうでなければ 'ClassCastException'が存在しないため)、' first == x.first'自体に期待される型がないので、コンパイラはそれを使用して過負荷を選択することはできません。つまり、私の説明によれば、代わりに 'val foo:Boolean = new Foo()。bar(" baz ")。asInstanceOf [Boolean]'を試す必要があります。 –

2

演算子は、javaのObject.equalsメソッドに似たセマンティクスでscalaコンパイラによって提供されます。これは、常にブール値を返す理由です。だから私は、あなた自身の演算子を実装したときにスカラーがその結果をブール値にキャストしようとしていると仮定します。

+0

私はあなたの答えを理解していますが、私はまだ予想外の結果を感じています。実際のケースでは、私たちはすでに別のアプローチを使用して解決していますが、この例外は私を驚かせるものです。ありがとう – maborg

+0

私はそれをよりよく理解するためにreplとインラインでテストしていますが、まだ私は少しバフです:) – maborg

3

更新されたバージョン(ブール値を返す==)は私のために働きます。

奇妙なエラーの理由は、おそらくあなたがREPLで試していて、Firstクラスを再定義したが、Secondではないからです。

REPLは、通常はスカラでは不可能なクラスと変数を再定義できるようにトリッキーですので、基本的にはFirstという2つのバージョンがあります。そして、あなたのSecond定義は引き続き古いものを参照します。 new First()のコンストラクタには新しいものがあるため、不一致です。

Secondクラスを再定義するだけで問題なく動作します。

== BTWを再定義するのに間違いはありませんが、これらの場合はequalsを上書きすることがより一般的です。これは同じ効果があります。 ==のデフォルトの実装ではequalsが呼び出されます。そのため、1つの問題は、下位の人がサブクラスの1つにあるequalsをオーバーライドして、期待したことをしないことで困惑してしまうことです。

+0

はい、問題は私がREPLでインタラクティブにそれを変更することによって引き起こされました。それは最初から始まります。 thnks – maborg

+0

==の代わりにequalsをオーバーライドしますが、== callが私の例が失敗する理由と等しい場合は? – maborg

+0

あなたの例は、ブール値である必要がある間に文字列を返すようにオーバーライドするので失敗します – Dima

関連する問題