代码之家  ›  专栏  ›  技术社区  ›  vkubicki

如何避免类型参数擦除

  •  1
  • vkubicki  · 技术社区  · 7 年前

    我的代码使用Scala和Breeze线性代数库。我有类型的对象 DenseVector[Double] , DenseVector[Int] 等哪里 DenseVector 是一个类似数组的容器,具有用于数值计算的专用方法。我有时需要对包含的类型使用模式匹配。类型擦除迫使我引入一个trait和“包装”case类:

    sealed trait DenseVectorRoot
    case class DenseVectorReal(val data: DenseVector[Real]) extends DenseVectorRoot
    case class DenseVectorMatrixReal(val data: DenseVector[DenseMatrix[Real]]) extends DenseVectorRoot
    

    (其中 Real 只是的别名 Double ).

    模式匹配如下所示:

    def print(data: DenseVectorRoot) =
      data match {
        case DenseVectorMatrixReal(_) => println("Contains real matrices")
        case DenseVectorReal(_) => println("Contains real scalars")
      }
    

    我想摆脱 DenseVectorRoot 特质我尝试了以下操作:

    def print2(data: DenseVector[_ <: Any]) =
      data match {
        case _: DenseVector[Double] => println("Contains real matrices")
        case _: DenseVector[Int] => println("Contains real scalars")
      }
    

    但是类型参数会被删除。

    我应该如何修改 print2 使用类标记以便模式匹配工作?例如,通过在以下代码中打印正确的输出:

    val v0 = DenseVector(1.2, 1.5, 1.6)
    val v1 = DenseVector(3, 4, 5)
    
    val a = Array(v0, v1)
    a.map(print2)
    

    编辑

    我需要管理 Array 对于不同的容器,我的代码需要管理不同类型的数据(例如,对于 DenseVector[Real] 对于 DenseVector[Matrix[Real]] ). 我目前的设计是将所有东西存储在 Array[DenseVectorRoot] ,然后使用高阶函数处理数据,如 .map() . 每个函数都将在元素到元素的基础上进行模式匹配,以了解数据是否为 DenseVectorReal 或a DenseVectorMatrixReal ,并据此采取行动。

    这可能不是解决我的问题的最佳设计,但我不知道在编译时用户提供了什么类型的数据。我很高兴知道任何更好的设计!

    2 回复  |  直到 7 年前
        1
  •  1
  •   Community CDub    4 年前

    使用 TypeTag

    您可以请求编译器推断参数类型,并生成 TypeTag 为你。 然后可以使用 类型标签 检查特定类型,或者您可以 print 它用于调试目的。

    示例代码

    import scala.reflect.runtime.universe._
    
    def printType[A: TypeTag](a: List[A]): Unit = 
      println(if(typeTag[A] == typeTag[Double]) "Double" else "other")
    
    printType(List(1.0))
    printType(List(1))
    

    输出

    >Double
    >other
    
        2
  •  1
  •   Dima    7 年前

    使用类型类可以更好地完成这类工作:

      trait DenseContent[T] {
        def compute(v: DenseVector[T]): String
      }
      object DenseContent {
        implicit object _Real extends DenseContent[Real] {
          def compute(v: DenseVector[Real]) = "real"
        }
        implicit object _Int extends DenseContent[Int] {
          def compute(v: DenseVector[Int]) = "int"
        }
        // etc ...
      }
    
      def print2[T : DenseContent](data: DenseVector[T]) = println(
         implicitly[DenseContent[T]].compute(data)
      )