Case class copy() method abstraction

前端 未结 5 824
孤独总比滥情好
孤独总比滥情好 2021-01-02 02:08

I would like to know if it is possible to abstract the copy method of case classes. Basically I have something like sealed trait Op and then something like

相关标签:
5条回答
  • 2021-01-02 02:29

    You seem to be confusing copy with clone. The goal of copy is to make an almost identical copy, but with something changed. What that something might be depends on the parameters of the case class, so it's not possible to make it a common method.

    In the case of case class X(), it doesn't make much sense to have a copy method, as there's nothing there to be changed.

    On the other hand, clone is a Java method whose goal is to produce perfect copies of an object, which seems to be what you want.

    0 讨论(0)
  • 2021-01-02 02:30

    Upvoted Ben's answer. But what if you wanted to something like this:

    sealed trait Op 
    case class Push(value: Int, context:String) extends Op
    case class Pop(context:String) extends Op
    
    val stackOps = List(Push(3, "foo"), Pop("foo"))
    
    def copyToContext(newContext:String, ops:List[Op]): List[Op] = {
        // ... ?
    }
    
    val changedOps = copyToContext("bar", stackOps)
    
    // would return: List(Push(3, "bar"), Pop("bar"))
    
    0 讨论(0)
  • 2021-01-02 02:33
    1. What would be the benefit of a compiler generated copy method for case classes without any arguments? This would just return a new Foo, and not copy anything.
    2. To quote Lukas Rytz (I believe he implemented it):
    The copy methods are only generated if there is no member named"copy" in the class, directly defined or inherited.
    0 讨论(0)
  • 2021-01-02 02:35

    Why do you need to create identical copies of your case class instances? Case classes are, by default, immutable so can be safely shared.

    In any case, I don't think you can do what you're asking with default parameters:

    scala> trait Op { def copy():Op }          
    defined trait Op
    
    scala> case class Op1(v:Int) extends Op    
    <console>:6: error: class Op1 needs to be abstract, since method copy in trait Op of type ()Op is not defined
           case class Op1(v:Int) extends Op
    

    The compiler doesn't create methods with all combinations of the optional parameters in the defining class. The default values are inserted in the place where the method is called.

    0 讨论(0)
  • 2021-01-02 02:42

    As Mirko correctly pointed out, you cannot really abstract over copy method. I support Daniel's view, that cloning may be what you want, although I would wrap it with some helper code to reduce boilerplate.

    You can define a mixin trait with copy functionality and just mix it into your case classes then:

    trait ClonableAs[T] extends Cloneable { this: T => 
      def makeClone() = super.clone().asInstanceOf[T]
    }
    
    case class Foo(i: Int) extends ClonableAs[Foo]
    
    List(Foo(1), Foo(2), Foo(3)).map(_.makeClone())
    

    That way instead of adding an identical method to each of your case classes, you make them extend the helper trait, which makes them cleaner and saves you some keystrokes.

    On the other hand, the cloning would make no sense for immutable objects, so I infer your classes have mutable state. I would advise you to reconsider if you really cannot make them immutable, and use that type of cloning only at last resort. Immutability will protect yourself from a class of errors.

    0 讨论(0)
提交回复
热议问题