假设我想构建一个记录列表,其中每个记录包含一些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]]更好的数据类型来表示其字段类型(和数字)仅在运行时才知道的记录列表?
谢谢。
答案 0 :(得分:2)
您的问题是您在隐式范围内没有正确的Ordering
实例。一个不存在的原因是Ordering[Any]
是非感性的。即使我们有这样一个实例,它的目的是什么,比较String
和Int
是什么意思?还是Object
和List
?你可以组成一个排序但它没用,因为没有办法获得关于Any
类型的任何有趣的东西。有一些复杂的方法可以达到你想要的效果,但这似乎表明存在设计问题,你可能想尝试重新思考你的方法。