声明Scala案例类有哪些缺点?
如果您正在编写使用大量漂亮,不可变数据结构的代码,则案例类似乎是天赐之物,只需一个关键字即可免费为您提供以下所有内容:
默认情况下一切都是不可变的
Getters自动定义
Decent toString()实现
兼容的equals()和hashCode()
Companion对象使用unapply()方法进行匹配
但是将不可变数据结构定义为案例类有什么缺点?
它对班级或其客户有什么限制?
您是否应该选择非案例类?
没有找到相关结果
已邀请:
5 个回复
系漏
稀瓣囊
) Getters自动定义 可以在任何类中使用
加上参数 体面的
实施 是的,非常有用,但如有必要,可以手工操作任何课程 符合
和
结合简单的模式匹配,这是人们使用案例类的主要原因 用
方法进行匹配的伴随对象 也可以通过使用提取器在任何类上手动完成 这个列表还应该包括超级强大的复制方法,这是Scala 2.8最好的方法之一 那么糟糕的是,案例类只有少数真正的限制: 您不能使用与编译器生成的方法相同的签名在伴随对象中定义
但在实践中,这很少是一个问题。改变生成的apply方法的行为可以保证让用户感到惊讶,并且强烈建议不要这样做,这样做的唯一理由就是验证输入参数 - 在主构造函数体中最好的任务(使用ѭ7时也可以进行验证) 你不能子类 没错,尽管案例类本身仍然可以成为后代。一种常见的模式是构建特征的类层次结构,使用案例类作为树的叶节点。 值得注意的是
修饰符。必须在同一文件中声明具有此修饰符的特征的任何子类。当对特征的实例进行模式匹配时,编译器可以在没有检查所有可能的具体子类时警告您。与案例类结合使用时,如果代码在没有警告的情况下编译,则可以为您提供非常高级别的置信度。 作为Product的子类,案例类的参数不能超过22个 没有真正的解决方法,除了停止使用这么多参数滥用课程:) 也... 有时提到的另一个限制是Scala(目前)不支持懒惰参数(如
s,但作为参数)。解决方法是使用副名称param并将其分配给构造函数中的lazy val。不幸的是,by-name params不会与模式匹配混合,这会阻止该技术与case类一起使用,因为它会破坏编译器生成的提取器。 如果您想要实现高功能的惰性数据结构,这是有用的,并且希望通过在未来的Scala版本中添加惰性参数来解决这个问题。
拈吉勉犬姆
时,你宣布了很多功能。这将降低您将来更改课程的灵活性。 例如,
在构造函数参数上有一个
方法。当你第一次写你的课时你可能不在乎,但是,后者可能决定你想要平等忽略其中一些参数,或做一些不同的事情。但是,客户端代码可能会在平均时间内写入,这取决于
的相等性。
补蹲农界维
此外,添加新的Prod类不需要对现有代码进行任何更改:
相反,添加新方法需要修改所有现有类。
案例类解决了同样的问题。
添加新方法是本地更改。
添加新的Prod类需要更改所有模式匹配。
视频选择4.6模式匹配的成绩单 这两种设计都非常精细,在它们之间进行选择有时是风格问题,但是有一些标准很重要。 一个标准可能是,您是否经常创建新的表达子类,或者您更经常创建新方法?因此,它是一个标准,用于查看未来的可扩展性以及系统可能的扩展过程。 如果你所做的主要是创建新的子类,那么实际上面向对象的分解解决方案占了上风。原因是只使用eval方法创建一个新的子类非常简单且非常本地化,在功能解决方案中,您必须返回并更改eval方法中的代码并添加新案例它。 另一方面,如果你所做的将创建许多新方法,但类层次结构本身将保持相对稳定,那么模式匹配实际上是有利的。因为,模式匹配解决方案中的每个新方法都只是一个本地更改,无论是将其放在基类中,还是放在类层次结构之外。然而,诸如在面向对象分解中显示的新方法将需要新的增量是每个子类。所以会有更多的部分,你必须触摸。 因此,在二维中可扩展性存在问题,您可能希望在层次结构中添加新类,或者您可能希望添加新方法,或者两者都被称为表达式问题。 请记住:我们必须使用它作为一个起点而不是唯一的标准。
寇剩
引用
第6章:
。 这是我在本书中发现的众多内容之一。 要为案例类提供多个构造函数,了解案例类声明实际执行的操作非常重要。
如果查看Scala编译器为case类示例生成的代码,您将看到它创建了两个输出文件Person $ .class和Person.class。如果使用javap命令反汇编Person $ .class,您将看到它包含apply方法以及许多其他方法:
您还可以反汇编Person.class以查看它包含的内容。对于像这样的简单类,它包含另外20个方法;这个隐藏的膨胀是一些开发人员不喜欢案例类的原因之一。