2017-03-09 91 views
0

下面的類層次結構:爲什麼scala需要存在類型來限制泛型綁定?

trait Provider[A] { 
    def get(): Seq[A] 
} 

abstract class ProviderImpl[A] extends Provider[A] { 
    final override def get(): Seq[A] = Seq() 
} 

trait HasX { 
    def getX: Int 
} 

trait RefinedProvider[A <: HasX] extends Provider[A] 

class TypedProviderImpl extends ProviderImpl[HasX] with RefinedProvider[HasX] 

我希望能夠做到這一點:

val provider: RefinedProvider[_] = new TypedProviderImpl() 
provider.get() map (_.getX) 

但它不工作,因爲provider.get()返回類型爲Seq[Any]這似乎因爲它是RefinedProvider,所以get()應返回Seq[_ <: HasX]

問題:我可以用存在類型解決這個問題,但爲什麼編譯器不能爲我執行這個?

val provider: RefinedProvider[T] forSome { type T <: HasX } = ... 
+0

感謝@碧玉-M - 實際上,您的意見不回答這個問題:門票分規範,它說, 'A [_]'*總是等於'A [Any]'(如果我正確讀取的話)並且編譯器永遠不會應用更多的邊界。我也不知何故忘記了'[_ <:HasX]' - 我的用例比上面的更復雜,但我可以通過各種方法簽名來使它工作。你想做出完整的答案嗎? –

+0

該規範非常明確,默認情況下,通配符「_」爲「_>:Nothing <:Any」。請參閱http://www.scala-lang.org/files/archive/spec/2.11/03-types.html#existential-types,「存在類型的佔位符語法」。 –

回答

1

Ticket SI-2385表明這是簡單的部分規範將A[_]解釋爲A[T] forSome { type T >: Nothing <: Any },並且如果可能的話不會推斷更緊密的邊界。人們可能會懷疑該規範是否應該不被更新。

SI-6169似乎表明,如果推斷更緊密的界限,有些事情將停止工作。我不知道如何以及爲什麼。

一個小的妥協是可以縮短

val provider: RefinedProvider[T] forSome { type T <: HasX } 

val provider: RefinedProvider[_ <: HasX] 
0

這是由你造成的使用通配符_說明你的變量類型:val provider: RefinedProvider[_]_這意味着任何類型,你可以不喜歡它:

val provider = new TypedProviderImpl() // the compiler and IDE will auto infer **provider** type 

val provider: RefinedProvider[HasX] = new TypedProviderImpl() // explicitly provider type 
+0

我認爲問題是,爲什麼scala不使用wildCard類型的HasX,而我們不能將RefinedProvider放入與HasX及其子節點不同的東西。對我來說,這也是個謎團:) –

+0

在OP的防守中:編譯器將RefinedProvider [_]'解釋爲RefinedProvider [_ <:HasX]'似乎非常合理。由於'RefinedProvider'具有約束'A <:HasX'。 –

+0

這個例子被簡化了:在我的實際使用情況中,TypedProviderImpl是一個通過依賴注入傳入的完整類,所以我不能讓編譯器爲我輸入它們,遺憾的是。 –

相關問題