在Scala中的列表中使用“嵌套”类型

时间:2013-09-11 14:49:44

标签: scala javafx-2 scalafx

我正在使用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 个答案:

答案 0 :(得分:2)

你用霰弹枪攻击蚊子。这个例子可以在没有参数多态的情况下解决,使用普通的旧继承:

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)

}

没有错误,没有警告,您可以在同一个列表中混合使用这两种类型的对象。

答案 1 :(得分:1)

workWithList的方法签名看起来不对 - ListItemType类型来自哪里?这应该是def workWithList(list: ObservableList[ListItem[_]]) { ...吗?

如果是这样,那么在匹配情况下遇到的问题是由于类型擦除,JVM无法在运行时区分案例的类型签名。这可以解决,例如,将Type1,Type2和ListItem转换为case类(或手动为它们生成unapply方法),然后在匹配的情况下解构项,如下所示:

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列表而不是ObservableListFXCollections.observableArrayList),因此它们可能会影响此解决方案的适用性(和可能是定义ListItemType的地方。

workWithItem的方法签名很好,但不应该要求你尝试的asInstanceOf强制转换。