一个可能的解决方法是使用isInstanceOf
and asInstanceOf
。
container match {
case Container(x) if x.isInstanceOf[String] =>
println(x.asInstanceOf[String].toUpperCase)
case Container(x) if x.isInstanceOf[Double] =>
println(math.sqrt(x.asInstanceOf[Double]))
case _ => println("_")
}
这行得通,但它看起来一点也不优雅。isInstanceOf
Scala 的创建者Martin Odersky 教授说asInstanceOf
应该避免这种情况。
正如 Rob Norris 指出的那样,在Coursera的“Scala 函数式编程”课程的论坛上,按类型匹配是一种不好的做法:case foo: Bar => ...
. Scala 鼓励利用静态类型并避免在运行时检查类型。这与 Haskell/ML 世界的哲学是一致的。子句应该匹配构造函数,而不是匹配类型。case
为了解决Container
匹配问题,可以为每种类型定义一个特殊的容器:
class Container[+A](val value: A)
case class StringContainer(override val value: String)
extends Container(value)
case class DoubleContainer(override val value: Double)
extends Container(value)
现在将匹配构造函数,而不是类型:
container match {
case StringContainer(x) => println(x.toUpperCase)
case DoubleContainer(x) => println(math.sqrt(x))
case _ => println("_")
}
显然,我们可以unapply
在两个对象中定义方法,StringContainer
并DoubleContainer
使用与上面相同的匹配,而不是扩展Container
类:
case class Container[+A](val value: A)
object StringContainer {
def unapply(c: Container[String]): Option[String] = Some(c.value)
}
object DoubleContainer {
def unapply(c: Container[Double]): Option[Double] = Some(c.value)
}
但这又不起作用,因为 JVM 类型擦除。
可以在此处找到对 Rob Norris 帖子的引用,该帖子将我引向此答案:https ://class.coursera.org/progfun-002/forum/thread?thread_id=842#post-3567 。不幸的是,除非您注册了 Coursera 课程,否则您无法访问它。