【问题标题】:Scala case class unchangeable memberScala案例类不可更改成员
【发布时间】:2014-02-04 17:15:37
【问题描述】:

在 Scala 中,我有一个表示一些数据的案例类:

case class Foo( val start : Int, val end : Int )

而且我经常使用复制方法。

但是,我现在想要添加一个额外的成员作为标识符,因为我想要以下相等行为:

case class NewFoo( val id : Int, val start : Int, val end : Int )
{
    override def equals( any : Any ) = any match
    {
        case other : NewFoo => id == other.id
        case _ => false
    }
}

但是,我现在想防止用户在复制NewFoo 实例时更改id,因此,一旦创建NewFoo,其数据可能会更改,但其id 将始终保持不变。

案例类可以做到这一点吗?我怀疑不是,因为这并不是它们的设计目的。另一方面,我读过的案例类的定义是,它们是“应该完全依赖于它们的构造函数参数的普通且不可变的数据保存对象”,我的用例似乎没有破坏这个定义.

如果一个案例类不合适,有没有一种方法可以复制一个案例的功能,尤其是复制方法,而无需明确的案例类?我没有使用模式匹配。

【问题讨论】:

    标签: class scala case


    【解决方案1】:

    是的,您可以像这样手动实现copy 方法:

    sealed class NewFoo(val id: Int, val start: Int, val end: Int) {
      def copy(start: Int = start, end: Int = end) = new NewFoo(id, start, end)
    
      override def equals(any: Any) = any match {
        case other : NewFoo => id == other.id
        case _ => false
      }
    
      // don't forget to override `hashCode` with `equals`
      override def hashCode() = id.hashCode()
    }
    

    请注意,您还应该用equals 覆盖hashCode

    您还可以将您的班级设为sealed 以避免此equals 实现出现问题。

    另见Programming in Scala/Object Equality

    您还可以在没有 new (NewFoo(0, 0, 0)) 的情况下使用此伴随对象实现来保存模式匹配和实例创建:

    object NewFoo {
      def apply(id: Int, start: Int, end: Int) = new NewFoo(id, start, end)
      def unapply(f: NewFoo): Option[(Int, Int, Int)] = Some((f.id, f.start, f.end))
    }
    

    【讨论】:

    • 我认为您可以将 NewFoo 保留为 case class 原样,节省模式匹配能力。
    • 感谢有关 hashCode 的提醒,我只是将其省略了,因为它并不是问题的一部分。至于你的复制实现,那是完美的!我一直认为复制是一些“神奇的方法”,但当然,它只是一种方法,每个成员都作为参数,现有值作为默认值。非常感谢!
    • @dmitry:查看更新,我认为不应仅将case class 用于生成的applyunapply 方法。
    • @paulmdavies:case class 中没有 magic methods。查看更新 - 您甚至可以在没有 case class 的情况下使用模式匹配。
    • @senia - 不是用于生成应用的用例类。为什么不呢?
    猜你喜欢
    • 1970-01-01
    • 2014-07-29
    • 1970-01-01
    • 2014-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多