case class copy 'method' with superclass

后端 未结 7 2012
误落风尘
误落风尘 2020-12-05 07:16

I want to do something like this:

sealed abstract class Base(val myparam:String)

case class Foo(override val mypar         


        
7条回答
  •  悲哀的现实
    2020-12-05 07:30

    I think this is what extension methods are for. Take your pick of implementation strategies for the copy method itself.

    I like here that the problem is solved in one place.

    It's interesting to ask why there is no trait for caseness: it wouldn't say much about how to invoke copy, except that it can always be invoked without args, copy().

    sealed trait Base { def p1: String }
    
    case class Foo(val p1: String) extends Base
    case class Bar(val p1: String, p2: String) extends Base
    case class Rab(val p2: String, p1: String) extends Base
    case class Baz(val p1: String)(val p3: String = p1.reverse) extends Base
    
    object CopyCase extends App {
    
      implicit class Copy(val b: Base) extends AnyVal {
        def copy(p1: String): Base = b match {
          case foo: Foo => foo.copy(p1 = p1)
          case bar: Bar => bar.copy(p1 = p1)
          case rab: Rab => rab.copy(p1 = p1)
          case baz: Baz => baz.copy(p1 = p1)(p1.reverse)
        }
        //def copy(p1: String): Base = reflect invoke
        //def copy(p1: String): Base = macro xcopy
      }
    
      val f = Foo("param1")
      val g = f.copy(p1="param2") // normal
      val h: Base = Bar("A", "B")
      val j = h.copy("basic")     // enhanced
      println(List(f,g,h,j) mkString ", ")
    
      val bs = List(Foo("param1"), Bar("A","B"), Rab("A","B"), Baz("param3")())
      val vs = bs map (b => b copy (p1 = b.p1 * 2))
      println(vs)
    }
    

    Just for fun, reflective copy:

      // finger exercise in the api
      def copy(p1: String): Base = {
        import scala.reflect.runtime.{ currentMirror => cm }
        import scala.reflect.runtime.universe._
        val im = cm.reflect(b)
        val ts = im.symbol.typeSignature
        val copySym = ts.member(newTermName("copy")).asMethod
        def element(p: Symbol): Any = (im reflectMethod ts.member(p.name).asMethod)()
        val args = for (ps <- copySym.params; p <- ps) yield {
          if (p.name.toString == "p1") p1 else element(p)
        }
        (im reflectMethod copySym)(args: _*).asInstanceOf[Base]
      }
    

提交回复
热议问题