2011-03-17 8 views
13

¿Hay alguna manera de confiar en los métodos definidos en la clase de caso en un rasgo? Por ejemplo, copia: lo siguiente no funciona. Aunque no estoy seguro de por qué.confíe en los métodos de la clase de caso en el rasgo

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] 

Da:

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] 
        ^
+0

¿Por qué crees que el compilador puede llegar a una implementación (que hace lo que quieres) para cualquier firma de método? – Raphael

+0

Realmente no me importa, idealmente ni siquiera necesitaría definir una copia en el rasgo, y podría marcar de alguna manera que el rasgo solo se puede mezclar en las clases de casos. ¿Es eso posible? –

+0

No obtengo lo que quieres. Un método tiene que ser definido o abstracto, no hay "tal vez". – Raphael

Respuesta

5

supongo que tener método con copia el nombre de rasgo instruye compilador para no generar copia método en la clase de caso - por lo que en su ejemplo copia método no está implementado en la clase de caso . A continuación breve experimento con copia método implementado en rasgo:

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 
+1

See también http://www.scala-lang.org/node/6369 y la especificación de la sección 5.3.2 sobre las clases de casos donde esto se menciona explícitamente –

+3

Solución solo para decir que no hay solución :( –

+1

Downvoted, solo porque no lo hace proporcionar una alternativa. – Nicolas

1

Puede ejecutar repl con $ Scala -Xprint: Typer. Con el parámetro -Xprint: typer puedes ver qué sucede exactamente cuando creas un rasgo o una clase. Y verá desde la salida que el método "copiar" no se creó, por lo que el compilador solicita que lo defina usted mismo.

11

Una solución es declarado que su rasgo se debe aplicar a una clase con un método de copia:

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) 
} 

(por desgracia no se puede utilizar el parámetro implícito en el método de copia, como una declaración implícita no está permitido en la declaración de tipo)

Luego, su declaración es aceptable:

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

(probado en Scala REPL 2.8.1)

La razón por la cual su intento no funciona se explica en la solución propuesta por otros usuarios: su declaración copy bloquea la generación del método "case copy".

+4

Si bien esto funciona en muy pocos casos, la mayoría de los métodos de copia dependerán de los tipos abstractos, que no están permitidos fuera del refinamiento. –

+1

Además, el número de parámetros para el método "copia" debe coincidir exactamente con el número de parámetros de clases de casos utilizados en la subclase. Por lo tanto, el rasgo K no sería compatible con la clase de caso L si L tuviera 3 parámetros en lugar de 2. –

Cuestiones relacionadas