rely on methods of case class in trait

妖精的绣舞 提交于 2019-11-27 13:58:12

问题


Is there a way to rely on methods defined in case class in a trait? E.g., copy: the following doesn't work. I'm not sure why, though.

trait K[T <: K[T]] {
  val x: String
  val y: String
  def m: T = copy(x = "hello")
  def copy(x: String = this.x, y: String = this.y): T
}

case class L(val x: String, val y: String) extends K[L]

Gives:

error: class L needs to be abstract, since method copy in trait K of type 
(x: String,y: String)L is not defined
           case class L(val x: String, val y: String) extends K[L]
                      ^

回答1:


I suppose that having method with name copy in trait instructs compiler to not generate method copy in case class - so in your example method copy is not implemented in your case class. Below short experiment with method copy implemented in trait:

scala> trait K[T <: K[T]] {                                                                                   
     | val x: String                                                                                          
     | val y: String                                                                                          
     | def m: T = copy(x = "hello")                                                                           
     | def copy(x: String = this.x, y: String = this.y): T = {println("I'm from trait"); null.asInstanceOf[T]}
     | }

defined trait K

scala> case class L(val x: String, val y: String) extends K[L]                                                
defined class L

scala> val c = L("x","y")                                                                                     
c: L = L(x,y)

scala> val d = c.copy()                                                                                       
I'm from trait
d: L = null



回答2:


A solution is to declare that your trait must be applied to a class with a copy method:

trait K[T <: K[T]] {this: {def copy(x: String, y: String): T} =>
  val x: String
  val y: String
  def m: T = copy(x = "hello", y)
}

(unfortunately you can not use implicit parameter in the copy method, as implicit declaration is not allowed in the type declaration)

Then your declaration is ok:

case class L(val x: String, val y: String) extends K[L]

(tested in REPL scala 2.8.1)

The reason why your attempt does not work is explained in the solution proposed by other users: your copy declaration block the generation of the "case copy" method.




回答3:


You can run repl with $scala -Xprint:typer. With parameter -Xprint:typer you can see what exactly happening when you create trait or class. And you will see from output that method "copy" not created, so compiler requests to define it by yourself.



来源:https://stackoverflow.com/questions/5341120/rely-on-methods-of-case-class-in-trait

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!