Scala 在特征上依赖案例类的方法

Scala 在特征上依赖案例类的方法,scala,case-class,Scala,Case Class,有没有一种方法可以依赖trait中case类中定义的方法?复制:以下内容不起作用。但我不知道为什么 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]

有没有一种方法可以依赖trait中case类中定义的方法?复制:以下内容不起作用。但我不知道为什么

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]

我假设在trait中使用名为copy的方法会指示编译器不在case类中生成方法副本,所以在示例中,方法副本不会在case类中实现。下面是在trait中使用方法copy进行的简短实验:

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
scala>trait K[T案例类L(val x:String,val y:String)扩展了K[L]
定义类L
scala>val c=L(“x”,“y”)
c:L=L(x,y)
scala>val d=c.copy()
我来自英国
d:L=null

您可以使用$scala-Xprint:typer运行repl。使用参数-Xprint:typer,您可以看到在创建trait或类时发生了什么。您将从输出中看到方法“copy”未创建,因此编译器请求您自己定义它。

解决方案是声明您的特性必须应用于具有复制方法的类:

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)
}
(在REPL scala 2.8.1中测试)


其他用户提出的解决方案解释了您的尝试不起作用的原因:您的
copy
声明阻止了“
case copy
”方法的生成。

为什么您认为编译器可以提出一个实现(这正是您想要的)对于任何方法签名?我真的不在乎理想情况下我甚至不需要在trait中定义一个副本,并且能够以某种方式标记trait只能混合到case类中。这可能吗?我没有得到你想要的。方法要么是定义的,要么是抽象的,没有“可能”。我希望能够定义一个依赖于案例类“
copy
方法”的特性中的方法。不能这样做将导致大量重复的代码,没有真正的原因。它如何能够依赖一个不存在的方法?另请参见规范第5.3.2节关于案例类的部分,其中明确提到了这一点。如果仅针对r表示没有解决方案:(“名为copy的方法隐式添加到每个case类中,除非该类已经有一个具有该名称的成员(直接定义或继承),或者该类有一个重复的参数。”虽然这在极少数有限的情况下有效,但大多数复制方法将依赖于抽象类型,这在细化之外是不允许的必须与子类中使用的案例类参数的数量完全匹配。因此,如果L有3个参数而不是2个,那么特征K将与案例类L不兼容。
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)
}
case class L(val x: String, val y: String) extends K[L]