scala 我应该在声明案例类时使用 final 修饰符吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34561614/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 07:54:51  来源:igfitidea点击:

Should I use the final modifier when declaring case classes?

scalastatic-analysiscase-classscala-wartremover

提问by sscarduzio

According to scala-wartremoverstatic analysis tool I have to put "final" in front of every case classes I create: error message says "case classes must be final".

根据scala-wartremover静态分析工具,我必须将“final”放在我创建的每个案例类之前:错误消息说“案例类必须是最终的”。

According to scapegoat(another static analysis tool for Scala) instead I shouldn't (error message: "Redundant final modifier on case class")

根据替罪羊(Scala 的另一个静态分析工具),我不应该这样做(错误消息:“案例类上的冗余最终修饰符”)

Who is right, and why?

谁是对的,为什么?

回答by Dima

It is not redundant in the sense that using it does change things. As one would expect, you cannot extend a final case class, but you can extend a non-final one. Why does wartremover suggest that case classes should be final? Well, because extending them isn't really a very good idea. Consider this:

从使用它确实会改变事物的意义上说,它并不是多余的。正如人们所料,您不能扩展 final 类,但可以扩展非 final 类。为什么 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
// ????

Really? Bar(1,1)equals Bar(1,2)? This is unexpected. But wait, there is more:

真的吗?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) // ???

A copy of Barhas type Foo? Can this be right?

Bar有类型的副本Foo?这可以吗?

Surely, we can fix this by overriding the .equals(and .hashCode, and .toString, and .unapply, and .copy, and also, possibly, .productIterator, .productArity, .productElementetc.) method on Barand Baz. But "out of the box", any class that extends a case class would be broken.

当然,我们可以通过覆盖解决这个问题.equals(并且.hashCode,和.toString,和.unapply,和.copy,而且,可能的话,.productIterator.productArity.productElement等)上的方法BarBaz。但是“开箱即用”,任何扩展案例类的类都会被破坏。

This is the reason, you can no longer extend a case class by another case class, it has been forbidden since, I think scala 2.11. Extending a case class by a non-case class is still allowed, but, at least, in wartremover's opinion isn't really a good idea.

这就是原因,您不能再通过另一个案例类扩展案例类,从我认为 Scala 2.11 以来,它已被禁止。仍然允许通过非案例类扩展案例类,但至少在 wartremover 看来并不是一个好主意。