我知道关于泛型类型的类型擦除和模式匹配存在很多问题,但是我无法理解在我的案例中我应该从那些答案中做些什么,而且我无法在 Headers 中更好地解释它 .
下面的代码片段被简化以呈现我的情况 .
所以我有一个特点
trait Feature[T] {
value T
def sub(other: Feature[T]): Double
}
// implicits for int,float,double etc to Feature with sub mapped to - function
...
然后我上课了
class Data(val features: IndexedSeq[Feature[_]]) {
def sub(other: Data): IndexedSeq[Double] = {
features.zip(other.features).map {
case(e1: Feature[t], e2: Feature[y]) => e1 sub e2.asInstanceOf[Feature[t]]
}
}
}
我有一个像这样的测试用例
case class TestFeature(val value: String) extends Feature[String] {
def sub(other: Feature[String]): Double = value.length - other.length
}
val testData1 = new Data(IndexedSeq(8, 8.3f, 8.232d, TestFeature("abcd"))
val testData2 = new Data(IndexedSeq(10, 10.1f, 10.123d, TestFeature("efg"))
testData1.sub(testData2).zipWithIndex.foreach {
case (res, 0) => res should be (8 - 10)
case (res, 1) => res should be (8.3f - 10.1f)
case (res, 2) => res should be (8.232d - 10.123d)
case (res, 3) => res should be (1)
}
这种方式有效 . 如果我尝试使用 Data
的实例在 features
的相同索引中具有不同类型的子操作,我得到一个 ClassCastException
. 这实际上满足了我的要求,但如果可能,我想使用 Option
而不是抛出异常 . 如何使以下代码工作?
class Data(val features: IndexedSeq[Feature[_]]) {
def sub(other: Data): IndexedSeq[Double] = {
features.zip(other.features).map {
// of course this does not work, just to give idea
case(e1: Feature[t], e2: Feature[y]) if t == y => e1 sub e2.asInstanceOf[Feature[t]]
}
}
}
另外我对Scala缺乏经验,所以我希望获得有关此类结构的反馈 . 有没有其他方法可以做到这一点,哪种方式最有意义?
2 回答
泛型在运行时不存在,并且
IndexedSeq[Feature[_]]
已经忘记了即使在编译时类型参数是什么(@Jatin 's answer won' t允许您使用Feature[_]
的混合类型列表构造Data
) . 最简单的答案可能就是捕获异常(使用_1109642_和scala.util.control.Exception
中的opt
) . 但是,要回答所写的问题:您可以在运行时检查类:
或者在
Feature
中包含类型信息:更复杂的"proper"解决方案可能是使用Shapeless
HList
来保留列表中的类型信息:这样
subAll
只能为其所有元素匹配的l1
和l2
调用,这在编译时强制执行 . (如果你真的想做Option
,你可以在subtract
中有两个at
,一个用于同类型的Feature[T]
,一个用于不同类型的Feature[_]
,但是完全排除它似乎是一个更好的解决方案)你可以这样做:
然后:
给
Vector()