Структурные типы с генериками в Scala - PullRequest
0 голосов
/ 28 августа 2018

Я попытался определить структурный тип, который соответствует экземпляру с универсальным типом. Как в этом примере кода:

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 голосов
/ 28 августа 2018

Попробуйте

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

Подробнее: Структурные типы с универсальным типом

...