Adding a field to Scala case class?

2019-07-16 18:07发布

I've seen some blogs on the Pimp my Library pattern, and these seem to work well for adding behavior to classes.

But what if I have a case class and I want to add data members to it? As a case class I can't extend it (inheriting from a case class is deprecated/strongly discouraged). Will any of these pimp patterns allow me to add data to a case class?

标签: class scala case
2条回答
Root(大扎)
2楼-- · 2019-07-16 18:28

This is not the way to do. Just a proof of possibility. With this way you can get plenty of problems.

scala> :paste
// Entering paste mode (ctrl-D to finish)

case class A(i: Int)

class B(a: A){
  var s: String = ""
}

object B{
  val as = scala.collection.mutable.WeakHashMap[A, B]()
}

implicit def a2b(a: A) = B.as.getOrElseUpdate(a, new B(a))

// Exiting paste mode, now interpreting.

defined class A
defined class B
defined module B
a2b: (a: A)B

scala> val a = A(1)
a: A = A(1)

scala> a.s = "test"

scala> a.s
res0: String = test

WeakHashMap: A hash map with references to entries which are weakly reachable. Entries are removed from this map when the key is no longer (strongly) referenced. This class wraps java.util.WeakHashMap.

Note that due to case class's overridden equals method you get this funny behavior:

scala> A(2).s = "test2"

scala> A(2).s
res2: String = test2

so you should not use case class or use it with override def equals(that: Any) = this eq that.asInstanceOf[AnyRef].

查看更多
Rolldiameter
3楼-- · 2019-07-16 18:30

No - I don't see how you could make this work because the enriched instance is usually thrown away (note: newly the pimp-my-library pattern is called enrich-my-library). For example:

scala> case class X(i: Int, s: String)
defined class X

scala> implicit class Y(x: X)  {
   |     var f: Float = 0F
   |   }
defined class Y

scala> X(1, "a")
res17: X = X(1,a)

scala> res17.f = 5F
res17.f: Float = 0.0

scala> res17.f
res18: Float = 0.0

You would have to make sure you kept hold of the wrapped instance:

scala> res17: Y
res19: Y = Y@4c2d27de

scala> res19.f = 4
res19.f: Float = 4.0

scala> res19.f
res20: Float = 4.0

However, I find this not useful in practice. You have a wrapper; you're better off making this explicit

查看更多
登录 后发表回答