web-dev-qa-db-ja.com

ケースクラスを宣言するときにfinal修飾子を使用する必要がありますか?

scala-wartremover 静的解析ツールによると、作成するすべてのケースクラスの前に「final」を配置する必要があります。エラーメッセージは「ケースクラスはfinalでなければならない」と言います。

scapegoat (Scalaの別の静的解析ツール)によると、代わりにすべきではありません(エラーメッセージ:「ケースクラスの冗長な最終修飾子」)

誰が正しいのですか?

50
sscarduzio

それを使用すると物事が変わるという意味で冗長ではありません。予想どおり、最終ケースクラスを拡張することはできませんが、非最終クラスを拡張することはできます。なぜwartremoverは、ケースクラスが最終的なものであることを示唆していますかなぜなら、それらを拡張するのはあまり良い考えではないからです。このことを考慮:

_scala> case class Foo(v:Int)
defined class Foo

scala> class Bar(v: Int, val x: Int) extends Foo(v)
defined class Bar

scala> new Bar(1, 1) == new Bar(1, 1)
res25: Boolean = true

scala> new Bar(1, 1) == new Bar(1, 2)
res26: Boolean = true
// ????
_

本当に? Bar(1,1)Bar(1,2)?と等しいこれは予想外です。しかし、待って、もっとあります:

_scala> new Bar(1,1) == Foo(1)
res27: Boolean = true

scala> class Baz(v: Int) extends Foo(v)
defined class Baz

scala> new Baz(1) == new Bar(1,1)
res29: Boolean = true //???

scala> println (new Bar(1,1))
Foo(1) // ???

scala> new Bar(1,2).copy()
res49: Foo = Foo(1) // ???
_

BarのコピーのタイプはFoo?ですか?これは正しいのでしょうか?

確かに、_.equals_(および_.hashCode_、および_.toString_、および_.unapply_、および_.copy_をオーバーライドすることでこれを修正できます。また、おそらく_.productIterator_、_.productArity_、_.productElement_など)BarおよびBazのメソッド。しかし、「箱から出して」、ケースクラスを拡張するクラスはすべて壊れます。

これが、別のケースクラスによってケースクラスを拡張することができなくなったため、scala 2.11。ケース以外のクラスによってケースクラスを拡張することはまだ考えられているため、禁止されています。許可されていますが、少なくとも、ウォートレーバーの意見では、あまり良い考えではありません。

86
Dima