简体   繁体   中英

Scala case class unchangeable member

In Scala, I have a case class representing some data:

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

and I often use the copy method.

However, I've now reached the point where I'd like to add an extra member as an identifier, because I want the following equality behaviour:

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
    }
}

However, I'd now like to prevent the user changing the id when they copy a NewFoo instance, thus, once a NewFoo is created, its data can change, but its id will always remain the same.

Is this possible with case classes? I suspect not, since it's not really what they're designed for. On the other hand, a definition I've read of case classes is that they are "plain and immutable data-holding objects that should exclusively depend on their constructor arguments", a definition which doesn't seem to be broken by my use case.

If a case class is inappropriate, is there a way I can replicate the functionality of a one, particularly the copy method, without having an explicit case class? I'm not using pattern matching.

Yes, you could implement copy method manually like this:

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()
}

Note that you should also override hashCode with equals .

You could also make your class sealed to avoid problems with this equals implementation.

See also Programming in Scala/Object Equality .

You could also save pattern matching and instance creation without new ( NewFoo(0, 0, 0) ) with this companion object implementation:

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))
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM