推断类型参数

推断类型参数

问题描述:

我与一些的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) 
+0

是的,这就是我最终做的事情......这很不幸,因为创建生成器本身在现实中是相当乏味的,不仅仅是“新生成器”,因为我在问题中简化了它,而且我希望调用者能够避免必须在任何地方进行。哦,好的... – Dima

+0

看到编辑。它能解决你的问题吗? –

+0

是的,那是有效的...虽然不比'anyFoo [Foo,FooBarBuilder](foo,b)'短得多,但不像丑陋:) – Dima

如果我正确地阅读代码。该代码并不意味着这种类型只有一个AbstractFooBuilder工厂,这留给调用者指定要使用的工厂。

如果你可以使用隐式的,你可以做这样的事情

def anyFoo[T <: Foo](foo: Foo, b: Bar)(implicit factory: AbstractFooBuilder[T]): T = { 
     factory. 
      withBar(b). 
      withFoo(foo). 
      build 
} 
+0

是,调用者必须指定工厂,但感觉像它应该是可以避免_also_不必指定对象的类型,它建立,因为这是由工厂类型决定。 – Dima