2012-02-08 2 views
7

Скажем, у меня есть высшее kinded типасдерживающими Высшие-Kinded типы в Scala

SuperMap[Key[_],Value[_]]`. 

Предположим теперь, что у меня было что-то еще более конкретное, что необходимо, чтобы параметр типа для Key должен совпадать для Value; то есть, что-то вроде:

SuperDuperMap[T, Key[T], Value[T]] 

Далее предположим, что я не хочу просто любой T, но очень специфична, где T <: OtherT

SuperDuperPooperMap[T <: OtherT, Key[T], Value[T]] 

Можно ли это сделать в Scala? Это вообще плохая идея? Есть ли эквивалентный способ сделать это, что легче читать/писать/использовать?

ответ

11

Ваше заявление уже работает как предполагается, т. Е. Вы ограничиваете тип T, а также Key и Value. То, как вы написали это, однако, будет жаловаться Scala, если выпустить что-то вроде

scala> class Foo[T <: OtherT, Key[T], Value[T]] 
defined class Foo 

scala> new Foo[SpecialOtherT, Key[SpecialOtherT], Value[SpecialOtherT]] 
<console>:13: error: Key[SpecialOtherT] takes no type parameters, expected: one 
       new Foo[SpecialOtherT, Key[SpecialOtherT], Value[SpecialOtherT]] 

, так как типы обоих Key и Value уже даны вашим предыдущего заявления. Следовательно, это будет работать

scala> new Foo[SpecialOtherT, Key, Value] 
res20: Foo[SpecialOtherT,Key,Value] = [email protected] 

который, вероятно, не хочет, чтобы вы хотели. Вы можете сделать это, как этот

scala> class Foo[T <: OtherT, K <: Key[T], V <: Value[T]] 
defined class Foo 

scala> new Foo[SpecialOtherT, Key[SpecialOtherT], Value[SpecialOtherT]] 
res21: Foo[SpecialOtherT,Key[SpecialOtherT],Value[SpecialOtherT]] = [email protected] 

На нижней строке, так как типы Key и Value зависят исключительно от T это несколько излишним иметь все, что избыточную информацию при работе с Foo.Так почему бы не использовать внутреннее объявление типа так:

class Foo[T <: OtherT] { 
    type K = Key[T] 
    type V = Value[T] 
} 

Тогда вы бы иметь доступ к типам K и V из класса, но не нужно будет вводить его каждый раз, когда вы создаете новый ответ:

scala> new Foo[SpecialOtherT] 
res23: Foo[SpecialOtherT] = [email protected] 

scala> new Foo[Int] 
<console>:11: error: ... 
+0

Спасибо! Очень информативно. Мой единственный ответ на «Так почему бы не использовать объявление внутреннего типа» заключается в том, что я хочу иметь эти типы для K и V, которые вызывают при создании экземпляра. – duckworthd

+0

Я не уверен, что понимаю, потому что тип фактически выведен. В зависимости от вашего прецедента вы все равно можете использовать тип «снаружи», например. 'class Foo [T]; класс Bar [T] {тип Wee = Foo [T]}; def doSomething [T] (b: Bar [T]) (неявный mf: Manifest [Bar [T] #Wee]) {Console println mf} ', а затем' doSomething (новая панель [Double]) '. Согласен, это грязный пример. – fotNelton

3

Можно ли это сделать в Scala?

Что вы имеете в виду? Ты только что сделал!

Это вообще плохая идея?

Зачем это было? На самом деле это отличная идея! Для этого нужны более высокие типы.

Есть ли эквивалентный способ сделать это, что легче читать/писать/использовать?

Чтение - читается довольно хорошо для меня.

Письмо - написать/проверить/скомпилировать один раз, использовать везде.

Использование - Компилятор будет реконструировать (вывести) типы «везде».

+0

Пока мой код компилируется, он не может быть создан: X – duckworthd

2

Вы, наверное, что-нибудь более сложное, чем пара псевдонимов типа не нужны,

type SuperDuperMap[T, Key[_], Value[_]] = SuperMap[Key, Value] 

type SuperDuperPooperMap[T <: OtherT, Key[_], Value[_]] = SuperMap[Key, Value] 

Sample РЕПЛ сессию,

scala> new SuperDuperMap[Int, Option, List] {} 
res0: java.lang.Object with SuperDuperMap[Int,Option,List] = ... 

scala> new SuperDuperPooperMap[OtherT, Option, List] {} 
res1: java.lang.Object with SuperDuperPooperMap[OtherT,Option,List] = ... 
Смежные вопросы