Должен ли я использовать последний модификатор при объявлении классов case?
Согласно инструменту статического анализа scala-wartremover я должен поставить "final" перед каждым классом case, который я создаю: сообщение об ошибке гласит: "классы case должны быть final".
Согласно scapegoat (другой инструмент статического анализа для Scala) вместо этого я не должен (сообщение об ошибке: "избыточный конечный модификатор на классе case")
Кто прав и почему?
1 ответ:
Он не является избыточным в том смысле, что его использование действительно меняет вещи. Как и следовало ожидать, вы не можете расширить конечный класс case, но вы можете расширить не окончательный. Почему wartremover предполагает, что классы case должны быть окончательными? Ну, потому что расширять их-не очень хорошая идея. Рассмотрим это:
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
? Может ли это быть правдой?Конечно, мы можно исправить это, переопределив
Это причина, вы больше не можете расширить класс case другим классом case, это было запрещено с тех пор, я думаю, scala 2.11. Расширение класса case на класс, не являющийся case, по-прежнему допускается, но, по крайней мере, по мнению wartremover, это не совсем так. лучшая идея..equals
(и.hashCode
, и.toString
, и.unapply
, и.copy
, а также, возможно,,.productIterator
,.productArity
,.productElement
и т.д.) метод наBar
иBaz
. Но "из коробки", любой класс, который расширяет класс case будет сломан.