假设我们有一个泛型类 Container
:
case class Container[+A](value: A)
然后,我们想要将 Container
与 Double
和 Container
Any
进行模式匹配:
val double = Container(3.3)
var container: Container[Any] = double
为此,我们通常会写:
container match {
case c: Container[String] => println(c.value.toUpperCase)
case c: Container[Double] => println(math.sqrt(c.value))
case _ => println("_")
}
但是,编译器会给出两个警告,前两个案例各一个 . 例如,第一个警告说:"non-variable type argument String in type pattern Container[String] is unchecked since it is eliminated by erasure" . 由于擦除,在运行期间不可能区分不同类型的容器并且第一个捕获物将匹配 . 因此, Container[Double]
类型的容器将匹配第一个案例,该案例捕获 Container[String]
个对象,因此将在 Double
上调用 toUpperCase
方法,并抛出 java.lang.ClassCastException
.
如何匹配特定类型的 Container
参数化?
4 回答
一般来说rarry的答案是正确的,但是对于你的情况它可以简化,因为你的容器只包含泛型类型的单个值,所以你可以直接匹配该值的类型:
也许这会有所帮助
Edit:
正如Impredicative所指出的,Manifest已被弃用 . 相反,你可以做以下事情:
可能的解决方法是使用
isInstanceOf
和asInstanceOf
.这样可行,但它看起来并不优雅 . Scala的创建者Martin Odersky教授说应该避免
isInstanceOf
和asInstanceOf
.正如Rob Norris所指出的那样,在Coursera的“Scala中的函数式编程”课程的论坛上,按类型匹配是一种不好的做法:
case foo: Bar => ...
. Scala鼓励利用静态类型并避免在运行时检查类型 . 这符合Haskell / ML世界的哲学 .case
子句应匹配构造函数,而不是匹配类型 .要解决
Container
匹配问题,可以为每种类型定义一个特殊容器:现在构造函数将匹配,而不是类型:
显然,我们可以在两个对象
StringContainer
和DoubleContainer
中定义unapply
方法,并使用与上面相同的匹配,而不是扩展Container
类:但是,由于JVM类型擦除,这也不起作用 .
可以在此处找到Rob Norris帖子的引用,该帖子引导我找到这个答案:https://class.coursera.org/progfun-002/forum/thread?thread_id=842#post-3567 . 不幸的是,除非您已加入Coursera课程,否则无法访问它 .
注意:您还可以选择Miles Sabin的Shapeless library(already mentioned by Miles in 2012 here) .
你可以在Jaakko Pallari的“Ways to pattern match generic types in Scala”中看到一个例子