8

我开始使用 Scala。如果我希望将其参数公开为属性,我是否应该将一个类定义为案例类?它不会引入任何副作用吗?

4

4 回答 4

14

为案例类生成的样板代码在字节码中具有很小但非零的成本。除了copy方法之外,还有hashCode,equals以及toString伴随对象工厂方法。

更重要的是,从案例类派生类是不可取的。从案例类派生案例类确实会引起问题(编译器会对您大喊大叫)。特别是,copy(...)编译器不会生成覆盖方法,因此如果您尝试复制从案例类派生的案例类,您可能会遇到一些奇怪的失败模式。

如果你把你的案例类放在任何继承图的叶子上,你会没事的。

于 2010-08-31T03:40:04.187 回答
12

您将获得定义的任何参数的属性,它们将是 vals(即决赛)

case class User(name: String, group: String)
val user = User("jsmith", "admins")

// access both properties
println("name: %s group: %s".format(user.name, user.group))

您也可以通过常规(即非案例类)获得此行为:

// creates two final public properties as well
class User(val name: String, val group: String)

// creates read/write public properties
class User(var name: String, var group: String)
val user = new User("jsmith", "admins")
user.group = "guests"

Case 类还带来了许多其他的东西,例如相等、hashcode 和 toString 的有用实现,以及一个带有工厂方法的伴随对象,它消除了使用 new 的需要。

如您所见,不需要案例类来实现您想要的,但它可以让您快速实现目标。至于副作用,定义一个案例类会在幕后生成一些代码,以提供上一段中描述的内容。这些通常很有用,我倾向于不担心它们,但了解它们是件好事。

于 2010-08-31T03:04:21.173 回答
7

除了已经提到的几点之外,案例类在概念上与您在 Java 中所谓的“值类”很接近。当然,没有什么能阻止您编写可变案例类或功能繁重但数据很少的案例类,但这可能会让使用您的代码的其他人感到惊讶。根据经验,我会说在创建案例类之前至少三思而后行……

  • 需要可变状态
  • 当您不确定以后是否需要子类时
  • 如果它们的主要目的是计算事物(而不是代表事物),并且这些计算很复杂
  • 如果您需要对其行为进行细粒度控制(例如,您需要自定义模式匹配)
  • 当性能真的很重要时
  • 当您只需要“案例类功能”之一时,例如我会考虑使用案例类只是为了避免在构造函数参数前面键入“val”作为矫枉过正
于 2010-08-31T06:24:08.210 回答
4

其他答案都很好,但他们错过的一个真正风险是案例类具有值相等性,其行为与标准的面向对象的身份相等性非常不同。如果所有字段都相等,则两个 case 对象相等。这正是在某些情况下所需要的,但在其他情况下却非常出乎意料。特别是,将可变状态添加到值相等的东西是自找麻烦。你可以很容易地发现哈希码随时间变化的对象,从而导致 HashMap 损坏和其他类似的问题。

将某些东西声明为案例类以节省一些将您的属性声明为“val”的击键是错误的经济,并且有一天会咬你。

于 2010-08-31T12:04:19.267 回答