Scala 中具有泛型的结构类型

Structural types with generics in Scala

我试图定义一个结构类型,它与具有泛型类型的实例相匹配。就像在这个示例代码中一样:

class ExampleTest extends FlatSpec with Matchers {
  def add[T](container: {def add(s: T): Boolean})(element: T): Unit = {
    container.add(element)
  }

  val set = new java.util.HashSet[String]()
  add(set)("3")
  set.contains("3") shouldEqual true

  val list = new java.util.LinkedList[String]()
  add(list)("3")
  list.contains("3") shouldEqual true
}

但是我得到一个编译错误:

Parameter type in structural refinement may not refer to an abstract type defined outside that refinement def add[T](container: {def add(s: T): Boolean})(element: T): Unit = {

当我把方法中的泛型去掉,写成这样的代码时:

class ExampleTest extends FlatSpec with Matchers {
  def add(container: {def add(s: String): Boolean}): Unit = {
    container.add("3")
  }

  val set = new java.util.HashSet[String]()
  add(set)
  set.contains("3") shouldEqual true

  val list = new java.util.LinkedList[String]()
  add(list)
  list.contains("3") shouldEqual true
}

它可以编译,但出现运行时异常:

java.lang.NoSuchMethodException: java.util.HashSet.add(java.lang.String)

我的问题是: 如何正确定义结构类型,以便它可以与 Java 集合一起使用?

请注意,它不能用 Scala 集合替换它们(它将与 Java 库一起使用)。

尝试

import scala.language.reflectiveCalls

def add[T](container: {def add(s: Any): Boolean})(element: T): Unit = {
  container.add(element)
}

val set = new java.util.HashSet[String]()
add(set.asInstanceOf[{def add(s: Any): Boolean}])("3")
set.contains("3") shouldEqual true

val list = new java.util.LinkedList[String]()
add(list.asInstanceOf[{def add(s: Any): Boolean}])("3")
list.contains("3") shouldEqual true

java.util.HashSet#add(实际上是java.util.AbstractCollection#add)和java.util.LinkedList#add的签名是

boolean add(E e)

结构类型的反射调用在运行时解决。在运行时,由于类型擦除泛型 E 只是 Any(又名 Object)。

更多详情:Structural types with generic type