2012-04-05 10 views
6

Dada una definición de clase con el parámetro de tipo vinculado Animal[A <: String] parece que el compilador de Scala no infiere B <: String de Animal[B]. ¿Está permitida la inferencia? ¿Cómo ayudar al compilador a hacer la inferencia?¿Cómo se definen las clases de casos con miembros con parámetros de tipo no vinculado?

A continuación se muestra un ejemplo concreto con clases de casos donde la falta de esta inferencia es un problema.

Consideremos el siguiente jerarquía de clases caso:

sealed trait Person[+T <: Person[T]] 
case class Student() extends Person[Student] 
case class Professor() extends Person[Professor] 

I necesidad de definir una clase de caso University que puedo instanciar con una variable de tipo Person[_], por ejemplo val p: Person[_] = Student(). Pensé que esto iba a funcionar con la siguiente definición:

case class University(p: Person[_]) 

Pero esto no se compila con el error:

type arguments [Any] do not conform to trait Person's type parameter bounds [+T <: Person[T]] 

Si Ato el parámetro de tipo de la clase caso University compila (también compila con parámetros acotados si dejo caer la palabra clave case pero esto no es una opción en mi caso):

case class BoundUniversity[P <: Person[P]](p: Person[P]) 

pero esta versión no puede ser parametrizada instanciado con una variable sin límites del tipo Person[_]:

val p: Person[_] = Student() 
BoundUniversity(p) 

falla compilar con:

inferred type arguments [_$1] do not conform to method apply's type parameter bounds [P <: Person[P]] 

ocurre el mismo error de un método con un argumento atado como:

def general[P <: Person[P]](p: P) = println(p) 

por lo que este es no específico para los constructores de clase.

Dos preguntas:

  1. El tipo Person se define con límites de parámetros Person[+T <: Person[T]], de modo que cada instancia de este tipo está asegurado a respetar esos límites: val p: Person[P] implica que P <: Person[P]; ¿O me estoy perdiendo algo? Entonces, ¿cómo puedo aclarar esto al compilador para que no se queje?

  2. ¿Cómo/Puedo definir una clase de caso con miembros con un tipo de parámetro independiente como case class University(p: Person[_])?

+0

¿Es necesario que 'T' sea covariante? – leedm777

+0

@dave en mi caso particular 'T' necesita ser covariante, pero creo que esto no cambia el problema: vea el ejemplo introductorio. –

+0

Puede obtener un sitio usando [tipos abstractos] (http://docs.scala-lang.org/tutorials/tour/abstract-types.html), pero luego se vuelven [bastante invariantes] (http: // stackoverflow. com/a/5359015/115478). – leedm777

Respuesta

2

Un tipo X[_] casi nunca es lo que desea. Cuando usas _ en un tipo, básicamente estás diciendo que no te importa qué parámetro es ese, porque nunca necesitarás usarlo.

De todos modos, esto compila. Puede morderlo en el camino, los tipos existenciales son lo difícil que son, pero ...

case class University(p: Person[t] forSome { type t <: Person[t] }) 
+0

tipo existencial agradable, gracias! Esto compila, pero no se puede crear una instancia con 'val p: Person [_] = Student(); Universidad (p) '. El tipo 'Persona [_]' que mencioné proviene de una lista: 'Lista [Persona [_]] (Estudiante(), Profesor())'. Tenga en cuenta que 'List (Student(), Professor())' no se compila. Siento que hay un patrón aquí, pero no puedo señalarlo ... –

+0

En realidad, esto no muestra errores en mi Eclipse, pero no se compila con 'scalac'. Escriba mismtach, found 'Person [(some other) _1 (in method equal)) donde type (some other) _1 (in method equal) <: schemdesc.hierarchy.eval.Person [_0]', required 'Person [_ < : schemdesc.hierarchy.eval.Person [_0]] ' –

+0

@jullybobble La línea anterior compila - Lo probé. Si tienes un problema de compilación, estás haciendo algo diferente. Y no puede usar 'Persona [_]' - no funcionará. Debe usar el tipo existencial anterior si desea que funcione. –

Cuestiones relacionadas