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

发布于 2024-11-19 22:29:47 字数 1119 浏览 3 评论 0原文

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)

In Programming 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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

动次打次papapa 2024-11-26 22:29:47

这只是一种语法限制,而不是固有的。您可以通过以下方式声明它:

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

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
  }
}
紫﹏色ふ单纯 2024-11-26 22:29:47

(Q1)>>这是仅适用于推断类型的特殊情况吗? <<

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

(Q2)>>或者有什么方法可以明确提供类型? <<

不。不提供存在类型。它不是要绑定的自由变量(因为它已经被绑定)。

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

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

(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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文