Использование "вложенных" типов в списке в Scala

Я использую ScalaFX и JavaFX, и у меня есть этот код:

import scalafx.Includes._

class Type1(anInt: Int, ...)
class Type2(aString: String, ...)

class ListItem[T](internalValue:T, ...)

object Worker
{

   val list1 = FXCollections.observableArrayList[ListItem[Type1]]()
   val list2 = FXCollections.observableArrayList[ListItem[Type2]]()

   def workWithList(list:ObservableList[ListItemType]) {
      list.foreach(i => workWithItem(i))
   }

   def workWithItem(item:ListItem) {
      item match {
         case i:ListItem[Type1] => do something
         case i:ListItem[Type2] => do something else
      }
   }    

   workWithList(list1)
   workWithList(list2)

}

Моя проблема в том, что этот код не компилируется; он говорит, что я не могу использовать ObservableList[ListItem[Type1]] для workWithList метод, который ожидает ObservableList[ListItem].

Поскольку я играл с этим, некоторые варианты этого кода говорят, что есть неконтролируемые предупреждения, и что сопоставление с образцом не будет работать из-за стирания типа.

В идеале:

  • будет только один список, который может содержать объекты типа ListItem [Type1] и ListItem[Type2]
  • Я мог бы сделать сопоставление с образцом при работе с элементами, чтобы делать разные вещи в зависимости от того, с каким элементом работает
  • workWithItem может работать с любым типом элемента. В моем текущем коде мне пришлось изменить подпись на workWithItem(item:ListItem[_]) а затем сделать workWithItem(someItem.asInstanceOf[ListItem[_]]), Наверное, не правильная вещь!

Спасибо!

2 ответа

Решение

Подпись метода для workWithList выглядит неправильно - где ListItemType типа откуда? Должно ли это быть def workWithList(list: ObservableList[ListItem[_]]) { ...?

Если это так, то проблема, с которой вы столкнетесь в случаях совпадения, состоит в том, что из-за стирания типа JVM не может определить разницу во время выполнения между сигнатурами типов дел. Это можно обойти, например, превратив Type1, Type2 и ListItem в классы дел (или создав вручную неприменимые методы для них), а затем деконструируя элемент в случаях сопоставления, например так:

case class Type1(anInt: Int)
case class Type2(aString: String)

case class ListItem[T](internalValue:T)

object Worker
{

   val list1 = FXCollections.observableArrayList[ListItem[Type1]]()
   val list2 = FXCollections.observableArrayList[ListItem[Type2]]()

   def workWithList(list: ObservableList[ListItem[_]]) {
      list.foreach(i => workWithItem(i))
   }

   def workWithItem(item: ListItem[_]) {
      item match {
         case ListItem(i: Type1) => println(s"Have type 1: ${i.anInt}") //do something
         case ListItem(i: Type2) => println(s"Have type 2: ${i.aString}") //do something else
         case anythingElse => println(s"Unknown type: $anythingElse") //just as a safe default for now
      }
   }

   workWithList(list1)
   workWithList(list2)

}

Обратите внимание, что я работаю здесь без каких-либо специальных знаний о библиотеках FX (я пробовал использовать прямые списки Scala, а не ObservableList или же FXCollections.observableArrayList), поэтому они могут повлиять на применимость этого решения (и могут быть ListItemType определено).

Подпись метода для workWithItem в порядке, но asInstanceOf бросок, который вы пробовали, не обязателен.

Вы атакуете комара с дробовиком. Этот пример может быть решен без параметрического полиморфизма с простым наследованием:

import scalafx.Includes._
import javafx.collections.{FXCollections,ObservableList}

class ListItemType
class Type1(anInt: Int) extends ListItemType
class Type2(aString: String) extends ListItemType

class ListItem(val internalValue:ListItemType)

object Worker
{

   val list1 = FXCollections.observableArrayList[ListItem]()
   val list2 = FXCollections.observableArrayList[ListItem]()

   def workWithList(list:ObservableList[ListItem]) {
      list.foreach(i => workWithItem(i))
   }

   def workWithItem(item:ListItem) {
      item.internalValue match {
         case i:Type1 => println("do something")
         case i:Type2 => println("do something else")
      }
   }    

   workWithList(list1)
   workWithList(list2)

}

Нет ошибок, нет предупреждений, и вы можете смешивать оба типа объектов в одном списке.

Другие вопросы по тегам