Type extraction in Scala
I am pretty new to Scala and advanced programming languages. I try to solve the following problem.
I have got:
val s: Seq[SomeMutableType[_]]
I assume that all elements in the sequence are of the same type (but do not know which one at this point).
How may I call :
def proc[T](v0: SomeMutableType[T], v1: SomeMutableType[T]) { /* ... */ }
with something like
proc(s(0), s(1))
The compiler complains :
- type mismatch; found : SomeMutableType[_$351] where type _$351 required: SomeMutableType[Any] Note开发者_如何转开发: _$351 <: Any, but class SomeMutableType is invariant in type T. You may wish to define T as +T instead. (SLS 4.5)
I thought about that covariant thing, but I do not believe it makes sense in my case. I just want the compiler believe me when I say that s(0) and s(1) are of the same type! I usually do this via some casting, but I cannot cast to SomeMutableType[T] here since T is unknown due to erasure. Of course, I cannot change the definition of proc.
The problem is that you truly cannot make such a guarantee. For example:
scala> import scala.collection.mutable.Buffer
import scala.collection.mutable.Buffer
scala> val s: Seq[Buffer[_]] = Seq(Buffer(1), Buffer("a"))
s: Seq[scala.collection.mutable.Buffer[_]] = List(ArrayBuffer(1), ArrayBuffer(a))
See? You don't know that s(0)
and s(1)
are of the same type, because they may not be of the same type.
At this point, you should ask a question about what you want to accomplish, instead of asking how to solve a problem in how you want to accomplish it. They way you took won't work. Step back, think what problem you were trying to solve with this approach, and ask how to solve that problem.
For instance, you say:
I assume that all elements in the sequence are of the same type (but do not know which one at this point).
It may be that what you want to do is parameterize a class or method, and use its type parameter when declaring s
. Or, maybe, not have an s
at all.
I am new to Scala, but as far as I can see your problem is the use of a wildcard type parameter when you declare s:
val s: Seq[SomeMutableType[_]]
As far as I understand, type erasure will always happen and what you really want here is a parameterised type bound to where s is initialised.
For example:
scala> class Erased(val s: List[_])
defined class Erased
scala> new Erased(List(1,2,3)).s.head
res21: Any = 1
If instead you use
scala> class Kept[T](val s: List[T])
defined class Kept
scala> new Kept(List(1,2,3)).s.head
res22: Int = 1
Then the contents of s retain their type information as it is bound to T. i.e. This is exactly how you tell the compiler "that s(0) and s(1) are of the same type".
精彩评论