Define 'copy' method in trait for case cla

2019-07-18 18:30发布

问题:

Given simplified code example:

sealed trait A {

  val c1: String
  val c2: Int

  def copy[Z <: A](src: File) : Z

}

case class B(c1: String, c2: Int, src: File) extends A

case class C(c1: String, c2: Int, c3: MyClass, src: File) extends A

how do I define copy method in trait A so it will match generated one for case class and 'target' file? Given definition does typecheck and complains about missing method copy in classes B and C.

回答1:

scala compiler will not generate copy methods for case class that defines method with name copy.

scala -Xprint:typer -e "sealed trait A { def copy[T <: A](s: String):T };  case class B(x: Int, y:Int) extends A"

outputs:

/var/folders/fm/fm4b21vj6jl995ywlrd99t49tjthjc/T/scalacmd3413244935208502669.scala:1: error: class B needs to be abstract, since method copy in trait A of type [T <: this.A](s: String)T is not defined
sealed trait A { def copy[T <: A](s: String):T };  case class B(x: Int, y: Int) extends A
                                                              ^
one error found
[[syntax trees at end of                     typer]] // scalacmd3413244935208502669.scala
package <empty> {
  object Main extends scala.AnyRef {
    def <init>(): Main.type = {
      Main.super.<init>();
      ()
    };
    def main(argv: Array[String]): Unit = {
      val args: Array[String] = argv;
      {
        final class $anon extends scala.AnyRef {
          def <init>(): anonymous class $anon = {
            $anon.super.<init>();
            ()
          };
          sealed abstract trait A extends scala.AnyRef {
            def copy[T >: Nothing <: this.A](s: String): T
          };
          case class B extends AnyRef with this.A with Product with Serializable {
            <caseaccessor> <paramaccessor> private[this] val x: Int = _;
            <stable> <caseaccessor> <accessor> <paramaccessor> def x: Int = B.this.x;
            <caseaccessor> <paramaccessor> private[this] val y: Int = _;
            <stable> <caseaccessor> <accessor> <paramaccessor> def y: Int = B.this.y;
            def <init>(x: Int, y: Int): this.B = {
              B.super.<init>();
              ()
            };
            override <synthetic> def productPrefix: String = "B";
            <synthetic> def productArity: Int = 2;
            <synthetic> def productElement(x$1: Int): Any = x$1 match {
              case 0 => B.this.x
              case 1 => B.this.y
              case _ => throw new IndexOutOfBoundsException(x$1.toString())
            };
            override <synthetic> def productIterator: Iterator[Any] = runtime.this.ScalaRunTime.typedProductIterator[Any](B.this);
            <synthetic> def canEqual(x$1: Any): Boolean = x$1.$isInstanceOf[this.B]();
            override <synthetic> def hashCode(): Int = {
              <synthetic> var acc: Int = -889275714;
              acc = Statics.this.mix(acc, x);
              acc = Statics.this.mix(acc, y);
              Statics.this.finalizeHash(acc, 2)
            };
            override <synthetic> def toString(): String = ScalaRunTime.this._toString(B.this);
            override <synthetic> def equals(x$1: Any): Boolean = B.this.eq(x$1.asInstanceOf[Object]).||(x$1 match {
  case (_: this.B) => true
  case _ => false
}.&&({
              <synthetic> val B$1: this.B = x$1.asInstanceOf[this.B];
              B.this.x.==(B$1.x).&&(B.this.y.==(B$1.y)).&&(B$1.canEqual(B.this))
            }))
          };
          <synthetic> private object B extends scala.runtime.AbstractFunction2[Int,Int,this.B] with Serializable {
            def <init>(): this.B.type = {
              B.super.<init>();
              ()
            };
            final override <synthetic> def toString(): String = "B";
            case <synthetic> def apply(x: Int, y: Int): this.B = new B(x, y);
            case <synthetic> def unapply(x$0: this.B): Option[(Int, Int)] = if (x$0.==(null))
              scala.this.None
            else
              Some.apply[(Int, Int)](Tuple2.apply[Int, Int](x$0.x, x$0.y));
            <synthetic> private def readResolve(): Object = $anon.this.B
          }
        };
        {
          new $anon();
          ()
        }
      }
    }
  }
}