2012-04-05 3 views
6

Учитывая определение класса с параметром связанного типа Animal[A <: String] кажется, что компилятор Scala не делает вывод B <: String от Animal[B]. Можно ли сделать вывод? Как помочь компилятору сделать вывод?Как определить классы case с членами с несвязанными параметрами типа?

Ниже приведен конкретный пример с примерами классов, где недостаток этого вывода является проблемой.

Рассмотрим следующую иерархию классов: случай

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

Мне нужно определить тематическое класс University, который я могу создать экземпляр с переменной типа Person[_], например val p: Person[_] = Student(). Я думал, что это будет работать со следующим определением:

case class University(p: Person[_]) 

Но это не удается компиляции с ошибкой:

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

Если я связать параметр типа в случае класса University компилирует (он также компилирует с неограниченные параметры, если я уронить case ключевое слово, но это не вариант в моем случае):

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

но эта параметрическая версия не может быть экземпляр с неограниченным переменным типа Person[_]:

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

не удается составителем с:

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

Той же ошибка происходит из-за метод со связанным аргументом, таким как:

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

так это не специфичные для конструкторов классов.

Два вопроса:

  1. Тип Person определяется с параметрами границ Person[+T <: Person[T]], так что каждый экземпляр данного типа застрахована соблюдать эти границы: val p: Person[P] означает, что P <: Person[P]; или я что-то упускаю? Итак, как я могу сделать это понятным для компилятора, чтобы он не жаловался?

  2. Как я могу определить класс case с членами с несвязанным параметром типа, например case class University(p: Person[_])?

+0

Должен ли 'T' быть ковариантным? – leedm777

+0

@ dave в моем конкретном случае 'T' должен быть ковариантным, но я думаю, что это не меняет проблемы: см. Вводный пример. –

+0

Вы можете получить где-нибудь, используя [абстрактные типы] (http://docs.scala-lang.org/tutorials/tour/abstract-types.html), но затем они становятся [почти инвариантными] (http: // stackoverflow. ком/а/5359015/115 478). – leedm777

ответ

2

A тип X[_] вряд ли когда-либо того, что вы хотите. Когда вы используете _ по типу, вы в основном говорите, что вам все равно, что этот параметр, потому что вам никогда не понадобится его использовать.

В любом случае, это компилируется. Это может укусить вас по дороге, экзистенциальные типы - это сложный материал, который они представляют, но ...

+0

Хороший экзистенциальный тип, спасибо! Он компилируется, но не может быть создан с помощью команды «val p: Person [_] = Student(); Университет (р) '. Тип 'Person [_]' Я упоминал, что это список: «List [Person [_]] (Student(), Professor())'. Обратите внимание, что 'List (Student(), Professor())' не компилируется. Я чувствую, что здесь есть шаблон, но я не могу на него наложить ... –

+0

На самом деле это не показывает ошибок в моем Eclipse, но не компилируется с помощью 'scalac'. Тип mismtach, найденный 'Person [(некоторые другие) _1 (в методе равно)], где type (некоторые другие) _1 (в методе равно) <: schemdesc.hierarchy.eval.Person [_0]', required 'Person [_ < : schemdesc.hierarchy.eval.Person [_0]] ' –

+0

@jullybobble Вышеприведенная строка компилируется - я ее протестировал. Если у вас проблема с компиляцией, вы делаете что-то другое. И вы не можете использовать 'Person [_]' - это не сработает. Вы должны использовать экзистенциальный тип выше, если хотите, чтобы он работал. –

Смежные вопросы