Scala类型安全和类型擦除相关的问题

时间:2013-04-30 18:49:14

标签: scala type-erasure type-safety

假设我想构建一个记录列表,其中每个记录包含一些x个字段。但是,在编译时不知道字段的数量和字段的类型。仅在运行时,我们知道每个字段的字段数和类型。所以为了表示这个列表,我使用List [Array [Any]]。

用户应该能够从该列表中找到某个字段的最小(最大)值的记录。

以下是一个高度简化的示例代码:

class Data(val colValues: List[Array[Any]]) {
  def min(i: Int): Array[Any] = {
    colValues.minBy { _(i) }
  }
}

用户应该能够以这种方式使用它:

val rawData = List(Array("a", 20, "z", "m", 3.0), Array("b", 10, "y", "f", 4.0), Array("c", 40, "z", "m", 2.0))
val d =  new Data(rawData)
val m1 = d.min(1)
val m2 = d.min(4)

以上代码无效。 Scala给出了这个错误:

  
      
  • 方法minBy的参数不够:(隐式cmp:Ordering [Any])数组[Any]。未指定的值参数cmp。
  •   
  • 没有为Any定义隐式排序。
  •   

事实上,正如预期的那样,Scala会在此列表中调用高阶方法时抱怨,例如maxBy,sortWith和sum。

所以我将代码修改为:

class Data(val colValues: List[Array[Any]]) {
  def withType(x: Any) = x match {
          case i: Int => i
          case l: Long => l
          case f: Float => f
          case d: Double => d
  }

  def min(i: Int): Array[Any] = {
    colValues.minBy { x:Array[Any] => withType(x(i)) }
  }
}

此代码按预期编译和运行。但是,我觉得必须有比这更优雅的解决方案。另外,如果使用String类型的字段索引调用min方法,则上述代码将不起作用。

在Array [Any]的情况下,是否有更好的方法来处理类型擦除和类型安全性,其中数组存储不同类型的元素,并且其类型仅在运行时才知道?

此外,是否有比List [Array [Any]]更好的数据类型来表示其字段类型(和数字)仅在运行时才知道的记录列表?

谢谢。

1 个答案:

答案 0 :(得分:2)

您的问题是您在隐式范围内没有正确的Ordering实例。一个不存在的原因是Ordering[Any]是非感性的。即使我们有这样一个实例,它的目的是什么,比较StringInt是什么意思?还是ObjectList?你可以组成一个排序但它没用,因为没有办法获得关于Any类型的任何有趣的东西。有一些复杂的方法可以达到你想要的效果,但这似乎表明存在设计问题,你可能想尝试重新思考你的方法。