推断类型参数
我与一些的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
是第二个参数的唯一可能性......我想知道是否有一些我错过的技巧,这将有可能“推断”其他参数,只需指定一。
任何想法?
不幸的是,标准的伎俩分裂型参数,因为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
推断,解决你的问题。作为奖励,速度更快,如果您的类碰巧没有默认构造函数,则不会出现运行时错误。
如果您的方法并不总是需要创建构建器,那么可以使用名义参数或() => 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)
如果我正确地阅读代码。该代码并不意味着这种类型只有一个AbstractFooBuilder
工厂,这留给调用者指定要使用的工厂。
如果你可以使用隐式的,你可以做这样的事情
def anyFoo[T <: Foo](foo: Foo, b: Bar)(implicit factory: AbstractFooBuilder[T]): T = {
factory.
withBar(b).
withFoo(foo).
build
}
是,调用者必须指定工厂,但感觉像它应该是可以避免_also_不必指定对象的类型,它建立,因为这是由工厂类型决定。 – Dima
是的,这就是我最终做的事情......这很不幸,因为创建生成器本身在现实中是相当乏味的,不仅仅是“新生成器”,因为我在问题中简化了它,而且我希望调用者能够避免必须在任何地方进行。哦,好的... – Dima
看到编辑。它能解决你的问题吗? –
是的,那是有效的...虽然不比'anyFoo [Foo,FooBarBuilder](foo,b)'短得多,但不像丑陋:) – Dima