Scala - implicit conversion with unapply

2019-04-25 02:23发布

问题:

I'd like an extractor to implicitly convert its parameters, but it doesn't seem to work. Consider this very simple case:

case class MyString(s: String) {}

implicit def string2mystring(x: String): MyString = new MyString(x)
implicit def mystring2string(x: MyString) = x.s

object Apply {
    def unapply(s: MyString): Option[String] = Some(s)
}

But I'm not able to use it as I would expect:

val Apply(z) = "a"  // error: scrutinee is incompatible with pattern type

Can anyone explain why it fails to convert the parameter from String to MyString? I would expect it to call string2mystring("a") on the fly. Clearly I could work around the issue by saying val Apply(y) = MyString("a"), but it doesn't seem like I should have to do that.

Note: This question is similar to this one, but 1) that one doesn't really have a good answer for why this is happening, 2) the example is more complex than it needs to be.

回答1:

Implicit conversions are not applied when pattern matching. That's not a bug or a problem with your code, it's simply a design decision of the creators of Scala.

To fix it, you should write another extractor that accepts a String — which in turn can call your implicit conversion.

Alternatively, you can try with a view bound, which seems to work as well, and will also work if you later define other implicit conversions to MyString:

object Apply {
  def unapply[S <% MyString](s: S): Option[String] = Some(s.s)
}