我有一对看起来像这样的类。有一个Generator基于一些类级别的值生成一个值,还有一个GeneratorFactory构造一个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.
我们可以使用这样的类。工厂在 的序列上工作Char,并generate产生 aString因为build给定了 a String。
val gb = GeneratorFactory[Char]()
val g = gb.build("this string")
val o = g.generate
这很好,并且String隐式处理类型,因为我们使用的是GeneratorFactory.
问题
Generator现在,当我想在不经过工厂的情况下构建一个时,问题就出现了。我希望能够做到这一点:
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
期望的输出
我想要的是一种简单地构造 aGenerator而不指定类型S并将其默认为的方法,Seq[T]以便我可以这样做:
val g2 = Generator('a', 'b', 'c')
val o2 = g2.generate
// o2 is of type Seq[Char]
我认为这将是用户最干净的界面。
有什么想法可以实现吗?