2017-04-14 182 views
1

我與一些的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是第二個參數的唯一可能性......我想知道是否有一些我錯過的技巧,這將有可能「推斷」其他參數,只需指定一。

任何想法?

回答

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推斷,解決你的問題。作爲獎勵,速度更快,如果您的類碰巧沒有默認構造函數,則不會出現運行時錯誤。

如果您的方法並不總是需要創建構建器,那麼可以使用名義參數或() => 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

0

如果我正確地閱讀代碼。該代碼並不意味着這種類型只有一個AbstractFooBuilder工廠,這留給調用者指定要使用的工廠。

如果你可以使用隱式的,你可以做這樣的事情

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

是,調用者必須指定工廠,但感覺像它應該是可以避免_also_不必指定對象的類型,它建立,因爲這是由工廠類型決定。 – Dima