8

私はこれを行うことができるようにしたい:

scala> val Int(i) = "1"
i: Int = 1

しかしInt、方法がありませんunapply

メソッドを既存のオブジェクトに暗黙的に追加する方法を説明するこの回答を見つけたので、試してみました。彼らが提供した解決策は機能しますが、残念ながらパターン マッチングには対応していません。ここに私が持っているものがあります:

object UnapplyInt {
  val IntRE = """^(\d+)$""".r
  def unapply(v: String): Option[Int] = v match {
    case IntRE(s) => Some(s.toInt)
    case _ => None
  }
}
implicit def int2unapplyInt(objA: Int.type) = UnapplyInt

これらのテスト ケースはすべて問題ありません。

val UnapplyInt(i) = "1"       // pattern matching with unapply is fine
val i = Int.unapply("1").get  // implicit conversion is fine

しかし、私が望むものは失敗します:

scala> val Int(i) = "1"
<console>:10: error: object Int is not a case class constructor, nor does it have an unapply/unapplySeq method
       val Int(i) = "1"
           ^

暗黙の変換が機能し、 とのパターン マッチングがunapply機能する場合、Scala はこれら 2 つのことを組み合わせて暗黙のパターン マッチングを行わないのはなぜでしょうか?

4

1 に答える 1

8

編集したがって、私の最初の推論はうまくいきませんでした。本当の理由は、Scala 言語仕様のセクション 8.1.8 にあります。

Syntax:
    SimplePattern ::= StableId ‘(’ [Patterns] ‘)’

つまり、extractor オブジェクトは安定している必要があり、暗黙的な変換は安定していません。エクストラクタが安定していなければならない理由についての説明はありません。それは、Scala がエクストラクターを式として扱いたくないためだと思います。

... match {
    foo(bar)(baz)
}

では、どれがコンストラクタで、どれがパターン変数でしょうか?

幸いなことに、これを行うことができ、問題なく動作します(ただし、コメントしたように、他の問題が発生します):

object Int {
    def unapply(v: String) = try Some(v.toInt)
        catch { case _: NumberFormatException => None }
}

val Int(i) = "5"

タイプIntとオブジェクトIntは異なる名前空間にあるためです。

于 2012-03-15T20:29:53.533 に答える