Не стоит откладывать на длинный текст, пункты довольно тривиальны, но для иллюстрации проблемы требуется немного кода. : -)
Настройка:
Скажем, я хотел бы создать черту, здесь смоделированную как Converter
некоторого вида, которая сама является универсальной, но имеет типизированный метод convert()
, который возвращает соответственно типизированный объект результата, скажем Container[T]
:
trait Converter {
def convert[T]( input: T ) : Container[T]
}
trait Container[T] // details don't matter
Мой вопрос касается ограничений типов для методов, в частности, для обеспечения равенства, и состоит из двух тесно связанных частей.
Часть 1: Теперь скажите, что существует специальный тип контейнера, который особенно подходит для содержимого на основе массива, например:
object Container {
trait ForArrays[U] extends Container[Array[U]]
}
Учитывая эту возможность, я бы хотел теперь специализировать конвертер и, в частности, тип возврата метода convert()
для специализированного типа Container.ForArrays
:
object Converter {
trait ForArrays extends Converter {
// the following line is rubbish - how to do this right?
def convert[E,T <: Array[E]]( input: T ) : Container.ForArrays[E]
}
}
Так что я могу сделать что-то вроде этого:
val converter = new Converter.ForArrays { ... }
val input = Array( 'A', 'B', 'C' )
val converted : Container.ForArrays[Char] = converter.convert( input )
По сути, я хочу, чтобы Scala, если известно, что тип преобразователя Converter.ForArrays
, также выводил специализированный тип возврата convert[Char]()
как Container.ForArrays[Char]
, то есть соответствующий тип контейнера плюс тип массива входных данных. Возможно ли это или что-то подобное, и если да, то как мне это сделать? Например. Как мне указать параметры типа / границы на convert () (то, что предоставляется, это просто замена - я понятия не имею, как это сделать). Да, и естественно, так что он все еще отменяет свой супер метод, иначе ничего не получится.
Часть 2: В качестве запасного варианта, если бы это было невозможно, я, конечно, мог бы перенести функцию преобразования в вариант, ориентированный на массив, например:
trait Converter // now pretty useless as a shared trait
object Converter {
trait ForValues extends Converter {
def convert[T]( input: T ) : Container[T]
}
trait ForArrays extends Converter {
def convert[E]( input: Array[E] ) : Container.ForArrays[E]
}
}
OK. Теперь скажите, что у меня есть еще более специализированный Converter.ForArrays.SetBased
, который может внутренне использовать набор элементов типа E (такой же, как тип элемента массива 'input'), чтобы совершать определенную магию во время преобразования. Набор теперь является параметром черты, однако так:
case class SetBased( set: Set[F] ) extends Converter.ForArrays {
// the following line is also rubbish...
def convert[E = F]( input: Array[E] ) : Container.ForArrays[E] = {...}
}
Опять же, речь идет о параметрах типа метода convert (). Сложность заключается в следующем: как мне приклеить параметр типа класса - F
- к параметру типа метода - E
- так, чтобы компилятор Scala позволял пользователю вызывать convert()
только с массивом, элементы соответствуют элементам набора? Пример:
val set = Set( 'X', 'Y', 'Z' )
val converter = new Converter.ForArrays.SetBased( set )
val input = Array( 'A', 'B', 'C' )
val converted : Container.ForArrays[Char] = converter.convert( input )