一些开源库如twitters似乎有一个将案例类标记为
final
的约定。
我的团队正在决定是否采用此约定,但我们尚不了解这样做的优点。目前我能感觉到的唯一可能的优点是它可以阻止从案例类中意外继承。
但是还有其他优点吗?它是否可以缩短编译时间或允许编译器添加内部优化?
我希望它能够帮助检测模式匹配中的缺失值,但它似乎也没有做到这一点。在这样的简单脚本中,编译器会针对
matchSealed
生成警告,但不会针对 matchFinal
:
sealed case class Sealed(one: Option[Int], two: Option[Int])
def matchSealed(s: Sealed): Unit = s match {
case Sealed(Some(i), None) => println(i)
}
final case class Final(one: Option[Int], two: Option[Int])
def matchFinal(f: Final): Unit = f match {
case Final(Some(i), None) => println(i)
}
我对
final
的印象是它比sealed
有更强的限制,所以奇怪的是这不会产生警告。
这是一些好处的解释:
最终案例类别不能由任何其他类别扩展。这意味着您可以对代码的行为方式做出更有力的保证。您知道没有人可以对您的类进行子类化、重写某些方法以及使一些愚蠢的事情发生。当您调试代码时,这非常有用 – 您不必在整个对象层次结构中寻找来找出实际调用了哪些方法。
当然,将类定为最终对象确实意味着您失去了某种形式的可扩展性。如果您确实发现自己希望允许用户实现功能,您应该将该功能包装在特征中并使用类型类模式。
如果您的案例类嵌套在特征或类中,出于范围界定的原因,您会得到不同的行为。如果没有修饰符,每个案例类实例都可以访问封闭的运行时特征/类实例。使用它,此类访问可能会丢失,具体取决于是否存在对外部作用域的引用,并且您会收到编译器警告。您是否需要路径依赖行为将决定您的选择。