Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pattern match on generic type in Scala?

Let's suppose we have a generic class Container:

case class Container[+A](value: A) 

We then want to pattern match a Container with a Double and a Container of Any:

val double = Container(3.3)   var container: Container[Any] = double 

To do this, we would normally write:

container match {     case c: Container[String] => println(c.value.toUpperCase)   case c: Container[Double] => println(math.sqrt(c.value))     case _ => println("_")   } 

However, the compiler gives two warnings, one for each of the first two cases. For example, the first warning says: "non-variable type argument String in type pattern Container[String] is unchecked since it is eliminated by erasure". Because of the erasure, it is impossible during runtime to distinguish between different kinds of containers and the first catch will be matched. As a consequence, container of type Container[Double] will be matched by the first case, which catches Container[String] objects, so toUpperCase method will be called on a Double and a java.lang.ClassCastException will be thrown.

How to match a Container parametrized by a particular type?

like image 288
Calin-Andrei Burloiu Avatar asked Apr 17 '13 09:04

Calin-Andrei Burloiu


People also ask

Does Scala have pattern matching?

Notes. Scala's pattern matching statement is most useful for matching on algebraic types expressed via case classes. Scala also allows the definition of patterns independently of case classes, using unapply methods in extractor objects.

How does Scala pattern matching work?

Pattern matching is a way of checking the given sequence of tokens for the presence of the specific pattern. It is the most widely used feature in Scala. It is a technique for checking a value against a pattern. It is similar to the switch statement of Java and C.

How do I use generic in Scala?

To use a generic class, put the type in the square brackets in place of A . Class Apple and Banana both extend Fruit so we can push instances apple and banana onto the stack of Fruit . Note: subtyping of generic types is *invariant*.

What is case class and pattern matching in Scala?

It is defined in Scala's root class Any and therefore is available for all objects. The match method takes a number of cases as an argument. Each alternative takes a pattern and one or more expressions that will be performed if the pattern matches. A symbol => is used to separate the pattern from the expressions.


2 Answers

In general rarry's answer is correct, for your case however it can be simplified, because your container only contains a single value of a generic type, so you can match on that value's type directly:

container match {   case Container(x: String) => println("string")   case Container(x: Double) => println("double")   case _ => println("w00t") } 
like image 112
drexin Avatar answered Oct 02 '22 16:10

drexin


Maybe this will help

 def matchContainer[A: Manifest](c: Container[A]) = c match {       case c: Container[String] if manifest <:< manifest[String] => println(c.value.toUpperCase)       case c: Container[Double] if manifest <:< manifest[Double] => println(math.sqrt(c.value))       case c: Container[_] => println("other")     } 

Edit:

As Impredicative pointed out, Manifest is deprecated. Instead you could do the following:

import reflect.runtime.universe._ def matchContainer[A: TypeTag](c: Container[A]) = c match {       case c: Container[String] if typeOf[A] <:< typeOf[String] => println("string: " + c.value.toUpperCase)       case c: Container[Double] if typeOf[A] <:< typeOf[Double] => println("double" + math.sqrt(c.value))       case c: Container[_] => println("other")     } 
like image 42
rarry Avatar answered Oct 02 '22 16:10

rarry