beetea beetea - 3 months ago 9
Scala Question

Case Classes w/ Option Parameters & Case Matching

I have a case class that has multiple parameters of which some are Options. Here is a simplified example:

case class Foobar(a: String, b: Option[String], c: Option[CustomClass])


I want to be able to match cases of Foobar where b and/or c is not None. For example, one case could be:

testResult match {
case Foobar("str1", Some(_), None) => "good"
case Foobar("str2", None, Some(_)) => "ok"
case _ => "bad"
}


Furthermore, I want to reference the case patterns via variables and this is where I'm stuck. I want to do something like the following:

val goodPat = Foobar("str1", Some(_), None) // compile fail
val okPat = Foobar("str2", None, Some(_)) // compile fail
testResult match {
case `goodPat` => "good"
case `okPat` => "ok"
case _ => "bad"
}


Is something like this possible? Is there another way to specify "not None"? Is there another way to approach this problem?

EDIT: I'm adding more details and context to the question. I have a large List of 2-tuples representing unit tests for a particular function. The 2-tuples represent the input and expected output. Eg.

// imagine this list is much bigger and Foobar contains more Option parameters
val tests = List(
("test1", Foobar("idkfa", None, None)),
// I know these fail to compile but I need to do something like this
("test2", Foobar("idclip", Some("baz"), Some(_)),
("test3", Foobar("iddqd", Some(_), None)
)

tests.foreach(test => {
val (input, expected) = test
myFunction(input) match {
case `expected` => println("ok")
case _ => println("bad")
}
})

Answer

I think you seeking for something like this:

case class DoomOpt(s: String)
case class Foobar(a: String, b: Option[String], c: Option[DoomOpt])

def myFunction(s: String) = Foobar(s, None, None)

val tests = Map[String, PartialFunction[Foobar, Unit]](
    "idkfa" → { case Foobar("idkfa", None, None) ⇒ },
    "test2" → { case Foobar("idclip", Some("baz"), Some(_)) ⇒ },
    "test3" → { case Foobar("iddqd", Some(_), None) ⇒ },
    "idspispopd" → { case Foobar("idspispopd", Some(_), None) ⇒ }
  )

tests.foreach { case (input, checker) =>
  if (checker.isDefinedAt(myFunction(input)))
    println("ok")
  else
    println("bad")
}