0

I want to use a Scala extractor to match my custom type with a String (in that specific order, not String to Scala). Here is my code:

class Scala object Scala { def apply(s: String) = new Scala def unapply(sc: Scala) = Some("Scala") } class ExtendedString(s: String) { def unapply(sc: Scala): Option[String] = { Some(s) } } implicit def str2Scala(s: String): ExtendedString = { new ExtendedString(s) } Scala match { case "abc" => println("Aha!") case "def" => println("Yeah!") case "scala" => println("Scala!") } 

But it does not work. I get an error:

Error:(20, 9) type mismatch; found : String("abc") required: A$A109.this.Scala.type case "abc" => println("Aha!") ^ 

How can I fix it to make extractor work?

PS

My original idea was to provide an implicit converter to extend String class with ExtendedString class and then to implement unapply method there to make extraction possible.

3
  • Possible duplicate of enrich PartialFunction with unapply functionality Commented Oct 19, 2015 at 23:27
  • No, I don't think they are the same questions. I'm trying to match a custom type to string. A String class does not have unapply function to get my custom type. Commented Oct 20, 2015 at 12:27
  • You've tried to use implicit conversions in match which is not something scala works like. Scala match expression is not a scala generic expression, and implicits don't work there. It is explained in that question. On how to do that properly, see @Dylan answer. Commented Oct 20, 2015 at 12:42

1 Answer 1

2

There should be no need whatsoever for implicits if all you want is an extractor.

To define an extractor, you make an object with an unapply method. E.g.

object MyExtractor { def unapply(value: ValueBeingMatched): Option[ExtractedValue] = { ... } } 

Then you match a value using the extractor

val myValue: ValueBeingMatched = ... myValue match { case MyExtractor(extractedValue) => println(s"I got $extractedValue!") } 

If you want your extractor to come back with multiple values, the unapply should return an option of tuple:

object MyExtractor { def unapply(value: ValueBeingMatched): Option[(ResultType1, ResultType2, ...)] = { ... } } val myValue: ValueBeingMatched = ... myValue match { case MyExtractor(result1, result2, ...) => ... } 

I'm not clear on what you are trying to accomplish from your example code, so I'll make an example that maybe is relevant for you.

Let's say you make a custom Point class:

case class Point(x: Int, y: Int) 

And you want to be able to extract points from a String. In this case, the ValueBeingMatched is a String, and the ExtractedValue is a Point. I'll also define the extractor in the Point object. As for functionality, let's assume that a string like "12,8" corresponds to a Point(12, 8).

object Point { def unapply(s: String): Option[Point] = { val parts = s.split(",") // this is just example code, so I won't handle failures, // but if it did fail, you'd return a None instead of Some Some(Point(parts(0).toInt, parts(1).toInt)) } } 

Now that it's defined, you can match strings using the Point extractor:

val s = "3,4" s match { case Point(p) => // p is actually an instance of Point } 

edit to respond to feedback:

In order to match directly to a string, the value being matched must already be a String. So one way would be to add a converter method e.g.

instanceOfMyType.convertToString match { case "abc" => println("Aha!") } 

Or you would have to write an extractor to allow

instanceOfMyType match { case Extracted("abc") => println("Aha!") } 
Sign up to request clarification or add additional context in comments.

3 Comments

My goal was to make something different. I was trying to match not a string to custom type, but the opposite case: custom type to string.
MyType match { case "abc" => println("Aha!") }
(I've added a bit to my answer in response to your comments)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.