首页 文章

如何根据Scala中的类型重复使用?

提问于
浏览
3

我正在解析包含各种结构的文件,其中一个是具有异构值的映射 . 将 Map 解析到内存后,我想根据值类型对其进行过滤,以获取给定类型的子图 .

为了交谈,这里有一个简单的类似例子:

// the types I want to filter on
case class A(c: Char)
case class B(c: Char)

// an example for testing
val m: Map[Int, Any] = Map((1 -> A('x')), (2 -> B('p')),
                           (3 -> A('y')), (4 -> B('q')))

这是一个将 Map 过滤到Map [Int,A]的函数:

// a successful filter function based on A
def as(m: Map[Int, Any]): Map[Int, A] =
  for((int, a: A) <- m) yield (int -> a)

你可以想象几乎完全相同的功能“bs”也是成功的,但我不想写 . 相反,我以为我会写一个通用函数:

// a failed generic filter function
def typeFilter[T](m: Map[Int, Any]): Map[Int, T] =
  for((int, t: T) <- m) yield (int -> t)

所以,这是状态:

val aMap: Map[Int, A] = as(m) // works!
val bMap: Map[Int, B] = bs(m) // works!
val aMapGen: Map[Int, A] = typedFilter[A](m) // doesn't work! returns all of m
val bMapGen: Map[Int, B] = typedFilter[B](m) // doesn't work! returns all of m

现在我对此更加严谨,进入这个问题,似乎更加奇怪 . Map [Int,A]如何包含B值的映射?它编译为声明的事实似乎意味着它应该正确运行,但是当我打印aMapGen或bMapGen的内容时,我看到m的全部内容,包括具有不兼容类型的值 . 这是我在Scala中遇到的第一个问题,就像Java中类型擦除的挫折一样 .

我希望能解释为什么它的行为本来就如此,但我的主要目标是能够编写一些可重用的代码来根据类型进行过滤 . 否则,我将不得不为我列表中的所有类型复制/粘贴具有更改类型的函数 .

谢谢你的帮助 .

3 回答

  • 3

    由于类型擦除,这是失败的 . Scala在Java虚拟机上运行,它没有泛型 . 因此,有关泛型的信息在运行时不可用,就像在Java中一样 .

    为了解决这个问题,我推荐你How do I get around type erasure on Scala? Or, why can't I get the type parameter of my collections?

  • 3

    这是一个改进吗?

    scala> // an example for testing
    
    scala> val m: Map[Int, Any] = Map((1 -> A('x')), (2 -> B('p')),
         |                            (3 -> A('y')), (4 -> B('q')))
    m: Map[Int,Any] = Map(1 -> A(x), 2 -> B(p), 3 -> A(y), 4 -> B(q))
    
    scala> def typeFilter[T](m: Map[Int, Any]): Map[Int, T] =
         |   for((int, t: T) <- m) yield (int -> t)
    <console>:14: warning: abstract type pattern T is unchecked since it is eliminated by erasure
             for((int, t: T) <- m) yield (int -> t)
                          ^
    typeFilter: [T](m: Map[Int,Any])Map[Int,T]
    
    scala> import reflect._
    import reflect._
    
    scala> def typeFilter[T: ClassTag](m: Map[Int, Any]): Map[Int, T] =
         | for((int, t: T) <- m) yield (int -> t)
    typeFilter: [T](m: Map[Int,Any])(implicit evidence$1: scala.reflect.ClassTag[T])Map[Int,T]
    
    scala> typedFilter[A](m)
    <console>:17: error: not found: value typedFilter
                  typedFilter[A](m)
                  ^
    
    scala> typeFilter[A](m)
    res3: Map[Int,A] = Map(1 -> A(x), 3 -> A(y))
    
    scala> typeFilter[B](m)
    res4: Map[Int,B] = Map(2 -> B(p), 4 -> B(q))
    

    人们已经要求为特定类型的警告提供-Xfatal警告的能力 .

    在那一天到来之前,可能总是使用-Xlint -Xfatal-warnings编译并使用干净的床单制作您的床 .

  • 1
    • 编译器是否警告线路上的类型擦除
    for((int, t: T) <- m) yield (int -> t)
    

    • 为了在运行时检查类,可以使用隐式classTag:
    def typeFilter[T](m: Map[Int, Any])(implicit classTag:ClassTag[T]): Map[Int, T] =
      m.collect{ case (int, t:T) if classTag.isInstance(t) => (int -> t)}
    

相关问题