How do you explicitly specify a parameterized type for an existential type in Scala?
In Pro开发者_JAVA技巧gramming in Scala, the following example is given to show how to reference a Java class with wildcards. The method javaSet2ScalaSet
takes a type T. Typically, you can always explicitly supply a parameterized type. But in this case where (new Wild).contents
is existential, a normal type parameter is not acceptable.
The compiler is able to perform some magic and infer an appropriate parameter when javaSet2ScalaSet
is called without a type parameter. Viewing what the compiler supplies with scalac –Xprint:typer shows that it assigns a value of ?0 for T. This can’t be provided manually.
Is this a special case that only works for an inferred type, or is there some way to explicitly supply the type?
// This is a Java class with wildcards
public class Wild {
Collection<?> contents() {
Collection<String> stuff = new Vector<String>();
stuff.add("a");
stuff.add("b");
stuff.add("see");
return stuff;
}
}
import scala.collection.mutable.Set
import java.util.Collection
abstract class SetAndType {
type Elem
val set: Set[Elem]
}
def javaSet2ScalaSet[T](jset: Collection[T]): SetAndType = {
val sset = Set.empty[T] // now T can be named!
val iter = jset.iterator
while (iter.hasNext)
sset += iter.next()
return new SetAndType {
type Elem = T
val set = sset
}
}
val setAndType = javaSet2ScalaSet((new Wild).contents)
It's just a syntactic limitation, not an inherent one. Here's how you can declare it:
def javaSet2ScalaSet[C <: Collection[T] forSome { type T }](jset: C): SetAndType = {
val sset = Set.empty[T forSome { type T }]
val iter = jset.iterator
while (iter.hasNext)
sset += iter.next()
return new SetAndType {
type Elem = T forSome { type T }
val set = sset
}
}
(Q1) >> Is this a special case that only works for an inferred type. <<
The compiler does not infer the type of your Java collection to be of type Collection. It only knows that it is a collection with elements of some type.
(Q2) >> or is there some way to explicitly supply the type? <<
No. An existential type is not to be supplied. It is not a free variable to be bound (since it is bound already).
Look at it this way: suppose you were able to provide the type. You would then expect the compiler to check that the provided type matches the type of elements in your Java collection. But there is no way for the compiler to determine that. So in case they wouldn't match, you would anyhow only find out at runtime.
If you would like to tell the Scala-compiler that you know that the elements in the java collection are of type String (e.g. you want to call x.length) then you could cast the elements with asInstanceOf[String]. But that will not introduce type-safety. You will again only find out at run-time if it would be incorrect.
精彩评论