Scala - 使用unapply进行隐式转换

9

我希望提取器可以隐式转换其参数,但似乎不起作用。考虑这个非常简单的情况:

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)
}

但是我无法像预期的那样使用它:
val Apply(z) = "a"  // error: scrutinee is incompatible with pattern type

有人能解释一下为什么它无法将参数从String转换为MyString吗?我希望它会即时调用string2mystring("a")。显然,我可以通过说val Apply(y) = MyString("a")来解决这个问题,但是我不认为我应该这样做。
注意:这个问题类似于这个问题,但是1)那个问题并没有一个好的答案解释为什么会发生这种情况,2)示例比它需要的更加复杂。
1个回答

15

在模式匹配时不会应用隐式转换。这不是您的代码中存在bug或问题,而是Scala创建者的设计决策。

要解决这个问题,您可以编写另一个接受String的提取器——该提取器可以调用您的隐式转换。

或者,您可以尝试使用视图界定(view bound),这似乎也可以工作,并且如果以后定义其他对MyString的隐式转换,它也将起作用:

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

1
谢谢。有点令人失望。你知道做出这个决定的动机是什么吗? - dhg
没错,将 def unapply(p: String): Option[String] = Some(p) 添加到 Apply 中就可以了。所以我会选择这个方案。谢谢。 - dhg
@dhg 我编辑了答案 - 视图绑定似乎也可以起作用。 - Jean-Philippe Pellet
太棒了!视图界定是一个很好的解决方案。它不仅不需要为每种可能的类型编写额外的方法,而且还解决了我遇到的另一个问题:如果 unapply 使用元组,则由于类型擦除,您无法使用重载技巧。但是这个解决方案干净利落地解决了这个问题,并导致编译时错误的参数类型不正确:def unapply[S <% MyString](p: (S, Int)): Option[String] = Some(p._1.s + p._2) - dhg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接