我有一对看起来像这样的类。有一个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]
我认为这将是用户最干净的界面。
有什么想法可以实现吗?