我正在集成一些java api,看起来有点像这样(这些是java类,我只是简单地使用scala语法:
class AbstractFooBuilder[ActualType <: AbstractFooBuilder, WhatToBuild <: Foo] {
// ...
def withFoo(f: Foo): ActualType
def withBar(b: Bar): ActualType
// ...
def build: WhatToBuild
}
class FooBarBuilder extends AbstractFooBuilder[FooBarBuilder, FooBar]
class FooBazBuilder extends AbstractFooBuilder[FooBazBuilder, FooBaz]
// .. etc
有很多这些,我试图通过这样的方式减少重复这些foos的创建:
def anyFoo[T <: Foo, B <: AbstractFooBuilder[B, T] : Manifest](foo: Foo, b: Bar) = manifest
.runtimeClass
.newInstance
.withFoo(foo)
.withBar(bar)
.build
问题是,现在,要创建FooBar
,我必须写下这样的内容:
val foobar = new anyFoo[FooBar, FooBarBuilder](foo, bar)
比我想要的要长。具体来说,一旦FooBarBuilder
类型参数已知,FooBar
是第二个参数的唯一可能性......我想知道是否有一些我缺少的技巧,这将使得&#34;推断&#34;另一个参数,只需要指定一个。
有什么想法吗?
答案 0 :(得分:1)
不幸的是,分割类型参数的标准技巧在这里不起作用,因为B
取决于T
。
但是如何摆脱Manifest
并简化为
def anyFoo[T <: Foo](builder: AbstractFooBuilder[_, T])(foo: Foo, b: Bar) =
builder.withBar(b).withFoo(foo).build
?您将其称为anyFoo(new FooBarBuilder)(foo, b)
,因此推断出T
,解决您的问题。作为奖励,如果您的类没有默认构造函数,它会更快并且没有运行时错误。
如果您的方法并不总是需要创建构建器,则可以使用by-name参数或() => AbstractFooBuilder[_, T]
。
编辑:鉴于评论,这可能有效:
def mkBuilder[B <: AbstractFooBuilder[B, _] : Manifest]: B = // the complex creation code
anyFoo(mkBuilder[FooBarBuilder])(foo, b) // infers FooBar
问题是,您是否可以在无法访问mkBuilder
的情况下实施T
,但如果您的原始代码不需要Manifest[T]
,则应该可以。
甚至
implicit class AnyFoo[T, B <: AbstractFooBuilder[B, T]](builder: B) {
def apply(foo: Foo, b: Bar) = builder.withBar(b).withFoo(foo).build
}
mkBuilder[FooBarBuilder](foo, b)
答案 1 :(得分:0)
如果我正确阅读代码。代码并不意味着此类型只有一个AbstractFooBuilder
工厂,而是由调用者指定要使用的工厂。
如果你可以使用隐含,你可以做这样的事情
def anyFoo[T <: Foo](foo: Foo, b: Bar)(implicit factory: AbstractFooBuilder[T]): T = {
factory.
withBar(b).
withFoo(foo).
build
}