Scala中具有泛型的结构类型

时间:2018-08-28 06:26:43

标签: scala generics structural-typing scala-generics

我试图定义一个结构类型,该结构类型与具有泛型类型的实例匹配。像下面的示例代码一样:

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库一起使用)。

1 个答案:

答案 0 :(得分:1)

尝试

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