Использование "вложенных" типов в списке в 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)
}
Нет ошибок, нет предупреждений, и вы можете смешивать оба типа объектов в одном списке.