问题
With the following class hierarchy:
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]
I want to be able to do this:
val provider: RefinedProvider[_] = new TypedProviderImpl()
provider.get() map (_.getX)
But it doesn't work, because the return type of provider.get()
is Seq[Any]
which seems wrong to me because it's a RefinedProvider
, so get()
should return a Seq[_ <: HasX]
.
Question: I can fix the problem with an existential type, but why can't the compiler enforce this for me?
val provider: RefinedProvider[T] forSome { type T <: HasX } = ...
回答1:
Ticket SI-2385 suggests this is simply part of the spec to interpret A[_]
as A[T] forSome
{ type T >: Nothing <: Any }
and not infer tighter bounds if possible. One could wonder whether the spec shouldn't be updated then.
Ticket SI-6169 seems to suggest that some things would stop working if tighter bounds were inferred. I'm not sure how and why though.
A small compromise is that you can shorten
val provider: RefinedProvider[T] forSome { type T <: HasX }
to
val provider: RefinedProvider[_ <: HasX]
回答2:
This is caused by you are using wildcard: _
to state your variable type: val provider: RefinedProvider[_]
, _
it means Any type, you can do it like:
val provider = new TypedProviderImpl() // the compiler and IDE will auto infer **provider** type
or
val provider: RefinedProvider[HasX] = new TypedProviderImpl() // explicitly provider type
来源:https://stackoverflow.com/questions/42696319/why-does-scala-require-existential-types-to-restrict-a-generic-bound