如何在Scala中为存在类型显式指定参数化类型?

时间:2011-07-15 03:54:14

标签: java scala wildcard type-systems existential-type

Scala编程 中,给出以下示例以说明如何使用通配符引用Java类。方法javaSet2ScalaSet采用类型T.通常,您始终可以显式提供参数化类型。但在(new Wild).contents存在的情况下,普通类型参数是不可接受的。

在没有类型参数的情况下调用javaSet2ScalaSet时,编译器能够执行一些魔法并推断出适当的参数。查看编译器使用scalac -Xprint:typer提供的内容,表明它为T赋值为?0。无法手动提供。

这是一个特殊情况,只适用于推断类型,还是有某种方式明确提供类型?

  // 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)

2 个答案:

答案 0 :(得分:1)

这只是一个句法限制,而不是固有的限制。以下是您可以声明的方式:

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
  }
}

答案 1 :(得分:0)

(Q1)&gt;&gt;这是一种特殊情况,仅适用于推断类型。 &LT;&LT;

编译器不会将Java集合的类型推断为Collection类型。它只知道它是一个包含某种类型元素的集合。

(Q2)&gt;&gt;或者有没有办法明确提供类型? &LT;&LT;

没有。不提供存在类型。它不是一个被绑定的自由变量(因为它已被绑定)。

以这种方式看待它:假设你能够提供类型。然后,您希望编译器检查提供的类型是否与Java集合中的元素类型匹配。但编译器无法确定这一点。所以万一他们不匹配,你无论如何只能在运行时找到。

如果您想告诉Scala编译器您知道java集合中的元素是String类型(例如,您想调用x.length),那么您可以使用asInstanceOf [String]强制转换元素。但这不会引入类型安全。您将再次仅在运行时发现它是否不正确。