2

我正在使用 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[_]]). 可能不是正确的做法!

谢谢!

4

2 回答 2

2

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

如果是这样,那么您将在匹配案例中遇到的问题是,由于类型擦除,JVM 无法在运行时区分案例的类型签名。例如,可以通过将 Type1、Type2 和 ListItem 转换为案例类(或为它们手动生成 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 列表而不是ObservableListor FXCollections.observableArrayList),因此它们可能会影响此解决方案的适用性(并且可能ListItemType是定义的位置)。

workWithItem 的方法签名很好,但asInstanceOf您尝试的演员表不应该是必需的。

于 2013-09-11T15:16:56.170 回答
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)

}

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

于 2014-06-25T07:08:14.800 回答