为什么Scala有一个case object?

5

它不能通过参数初始化,并且只能与自身进行比较(单例)。因此,其等值和哈希代码函数没有任何优势。有人遇到过有用的情况吗?


5
有人遇到过一个案例,其中... 呵呵,我笑了。 - Jakob
当您想定义代数数据类型时,这非常有用:https://gleichmann.wordpress.com/2011/01/30/functional-scala-algebraic-datatypes-enumerated-types/ - alifirat
2
例如:Nonecase object。实际上,当您的“代数数据类型”中的某个实例应该被区分但没有任何参数时,您会使用 case 对象。就像 Option 一样,Some(v)case class,但 None 只是没有状态的 None。关于为什么 case 很有用,请参见:https://dev59.com/2m435IYBdhLWcg3wrSPN - dmitry
akka中有许多用作消息的案例对象,例如PoisonPillTick等。 - ymonad
@dmitry,请将其添加为答案! - Dragonborn
2个回答

10

你可以使用case对象代替枚举。

详细信息可以在此处找到:Scala中的Case对象与枚举比较


来自该问题的简化示例:

sealed trait Currency {
  def name: String
  def symbol: String
}

case object EUR extends Currency {
  val name = "EUR"
  val symbol = "€"
}

case object USD extends Currency {
  val name = "USD"
  val symbol = "$"
}

优点

  • 相比于枚举类型中的ID和名称,这种方式可以拥有更多的字段。
  • 在类型层次结构使用sealed关键字时,编译器会警告匹配不全的情况。

因此,这段代码:

val ccy: Currency = EUR
ccy match {
  case EUR =>
    println("Euro")
}

会导致

警告:(27,7)匹配可能不完全。
它将无法处理以下输入:USD
ccy match {

缺点

  • 没有“按名称获取”方法(Enumeration提供withName()
  • 无法迭代“所有”元素

5
我认为最重要的区别在于 case 对象 可以被序列化,而简单的对象则不能。

这使它们在使用 Akka-Remote 作为消息时非常有用。

编辑: 正如Rüdiger Klaehn指出的那样,我们从case关键字中还获得了其他好处。 还有:

  • hashCode 实现
  • 一个有用的 toString 实现

对于类:

  • 模式匹配优化
  • 带有有用的applyunapply实现的伴随对象

(此列表可能不全!)


一个 case 对象也会有 hashCode 和 toString 实现。因此,case object Foo; foo.toString 将只返回 Foo,而 object Foo; Foo.toString 将返回类似于 Foo$@1bb485e7 的内容(每次运行时都不同!)。hashCode 也是如此:case 对象的 hashCode 在不同的 JVM 进程中将是相同的。 - Rüdiger Klaehn
等待 case 关键字不会使类可序列化,对吧? - Dragonborn
@Dragonborn 正相反:case 关键字使一个类/对象成为 Serializable(以及其他一些东西)。 - Sascha Kolberg
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Sascha Kolberg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接