У меня есть пара классов, которые выглядят примерно так. Там a Generator
, который генерирует значение, основанное на некоторых значениях уровня класса, и a GeneratorFactory
, который строит a Generator
.
case class Generator[T, S](a: T, b: T, c: T) {
def generate(implicit bf: CanBuildFrom[S, T, S]): S =
bf() += (a, b, c) result
}
case class GeneratorFactory[T]() {
def build[S <% Seq[T]](seq: S) = Generator[T, S](seq(0), seq(1), seq(2))
}
Вы заметите, что GeneratorFactory.build
принимает аргумент типа S
и Generator.generate
создает значение типа S
, но нет ничего типа S
, сохраненного Generator
.
Мы можем использовать классы, подобные этому. factory работает с последовательностью Char
, а generate
создает a String
, потому что build
задается String
.
val gb = GeneratorFactory[Char]()
val g = gb.build("this string")
val o = g.generate
Это нормально и обрабатывает тип String
неявно, потому что мы используем GeneratorFactory
.
Проблема
Теперь проблема возникает, когда я хочу построить Generator
, не пройдя через factory. Я хотел бы иметь возможность сделать это:
val g2 = Generator('a', 'b', 'c')
g2.generate // error
Но я получаю сообщение об ошибке, потому что g2
имеет тип Generator[Char,Nothing]
и Scala "Невозможно построить коллекцию типа Nothing с элементами типа Char на основе коллекции типа Nothing."
То, что я хочу, это способ сказать Scala, что значение по умолчанию S
похоже на Seq[T]
вместо Nothing
. Заимствуя синтаксис для параметров по умолчанию, мы могли бы подумать об этом как о чем-то вроде:
case class Generator[T, S=Seq[T]]
Недостаточные решения
Конечно, это работает, если явным образом расскажу генератору о том, каким должен быть его сгенерированный тип, но я думаю, что вариант по умолчанию будет более приятным (мой фактический сценарий более сложный):
val g3 = Generator[Char, String]('a', 'b', 'c')
val o3 = g3.generate // works fine, o3 has type String
Я думал о перегрузке Generator.apply
, чтобы иметь версию с одним родовым типом, но это вызывает ошибку, поскольку, по-видимому, Scala не может различать два определения apply
:
object Generator {
def apply[T](a: T, b: T, c: T) = new Generator[T, Seq[T]](a, b, c)
}
val g2 = Generator('a', 'b', 'c') // error: ambiguous reference to overloaded definition
Желаемый выход
Я хотел бы просто создать Generator
без указания типа S
и по умолчанию использовать его Seq[T]
, чтобы я мог:
val g2 = Generator('a', 'b', 'c')
val o2 = g2.generate
// o2 is of type Seq[Char]
Я думаю, что это был бы самый чистый интерфейс для пользователя.
Любые идеи, как я могу это сделать?