【问题标题】:Partial function matching a type erased type匹配类型删除类型的部分函数
【发布时间】:2016-01-11 07:45:12
【问题描述】:

在下面的代码中,我希望仅当 i 的类型为 A 时才调用 hitA。要检查的类型作为类型参数提供,因此它被类型擦除并且match 失败,给我一个编译器警告:

抽象类型模式 T 未被选中,因为它被擦除消除了

代码的期望输出是:

点击A

未命中

在当前版本中,当我运行代码时,我得到 Hit A,后跟 ClassCastException

我了解正在发生的事情以及为什么会出现警告和异常,但我不知道如何解决这个问题。我已阅读有关 TypeTags 的基本文章,并且了解如何在基本情况下使用它们,但我看不到如何使用 TypeTags 创建部分函数。

import scala.reflect.runtime.universe._


object TestMatch extends App {
  abstract class I

  class A extends I {
    def hitA() = println("Hit A")
  }

  class B extends I

  def processOpGen[T <: I : TypeTag](op: PartialFunction[I, Unit])(i: I) = {
    val fallback : PartialFunction[I, Unit] = {case _ => println("Not hit")}
    (op orElse fallback)(i)
  }

  def partialMatchGen[T <: I : TypeTag](op: T => Unit)(i: I) = {
    processOpGen[T] {
      case c: T => op(c) // can TypeTag be used here for matching somehow?
    }(i)
  }


  partialMatchGen[A](a => a.hitA())(new A)
  partialMatchGen[A](a => a.hitA())(new B)

}

【问题讨论】:

  • 这篇文章可能会有所帮助 - stackoverflow.com/questions/12218641/…。我正在用它来尝试回答这个问题。你想在这条线上匹配什么:case c: T =&gt; op(c)?
  • cT(或其子类)时,我想对c 执行一些操作。可以使用I 中的接口和A 中的实现,但我想这样做而不修改IA 类。

标签: scala pattern-matching type-erasure


【解决方案1】:

只要replace TypeTag with ClassTag:

import scala.reflect._

object Main extends App {
  abstract class I

  class A extends I {
    def hitA() = println("Hit A")
  }

  class B extends I

  def processOpGen[T <: I : ClassTag](op: PartialFunction[I, Unit])(i: I) = {
    val fallback : PartialFunction[I, Unit] = {case _ => println("Not hit")}
    (op orElse fallback)(i)
  }

  def partialMatchGen[T <: I : ClassTag](op: T => Unit)(i: I) = {
    processOpGen[T] {
      case c: T => op(c) // can TypeTag be used here for matching somehow?
    }(i)
  }

  partialMatchGen[A](a => a.hitA())(new A)
  partialMatchGen[A](a => a.hitA())(new B)
}

Processing...
Reused last reload result
[info] Loading project definition from /tmp/rendererL3zBdh8HOA/project/project
[info] Loading project definition from /tmp/rendererL3zBdh8HOA/project
[info] Set current project to rendererWorker (in build file:/tmp/rendererL3zBdh8HOA/)
[info] Reapplying settings...
[info] Set current project to rendererWorker (in build file:/tmp/rendererL3zBdh8HOA/)
[info] Formatting 1 Scala source {file:/tmp/rendererL3zBdh8HOA/}rendererWorker(compile) ...
[warn] Scalariform parser error for /tmp/rendererL3zBdh8HOA/src/main/scala/test.scala: Expected token RBRACKET but got Token(XML_START_OPEN,<,335,<)
[info] Compiling 1 Scala source to /tmp/rendererL3zBdh8HOA/target/classes...
[success] Total time: 11 s, completed Oct 13, 2015 5:16:45 PM
Now running...
[info] Running Main 
Hit A
Not hit
[success] Total time: 0 s, completed Oct 13, 2015 5:16:45 PM

【讨论】:

  • 哇。我没想到解决方案会这么好。我正在寻找一些解释为什么ClassTag 可以用于模式匹配而TypeTag 不能,但到目前为止我没有找到任何东西。你知道解释吗?
  • 我希望这是因为模式匹配通常无法区分例如具有不同类型参数的类型(比如List[Int]List[String]),并允许使用TypeTag 基本上可以保证这一点。
猜你喜欢
  • 2014-11-30
  • 1970-01-01
  • 2018-04-27
  • 2019-08-10
  • 2021-01-10
  • 1970-01-01
  • 2011-05-25
  • 2012-05-29
  • 2022-08-18
相关资源
最近更新 更多