2012-03-15 72 views
8

我希望能够做到这一点:斯卡拉 - 添加不应用到INT

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

Int没有一个unapply方法。

我找到了this answer,它给出了如何隐式添加方法到现有对象的说明,所以我试了一下。他们提供的解决方案的工作,但不幸的是不适合模式匹配。下面是我有:

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匹配作品,为什么斯卡拉不把这两样东西放在一起进行隐式模式匹配?

回答

8

编辑所以我最初的推理是不好的。真正的原因是从Section 8.1.8 of the Scala language spec

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

也就是说,提取对象必须是稳定的,并且隐式转换并不稳定。没有解释为什么提取器必须稳定;我怀疑这是因为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在不同的命名空间。

+0

哈!您提出的解决方案是我目前使用的。我对它并不满意,因为它需要两个不同的名称空间,这意味着我不能在同一个地方使用'Int.MaxValue'和'val Int(i)=“5”'。 – dhg 2012-03-15 20:35:35

+0

@dhg真的。现在我更多地思考这个问题,我认为我的回答中的推理是不正确的。真正的原因是模式表达式不能像正则表达式那样,因为Scala必须识别什么是构造函数,哪些变量是什么...... – Owen 2012-03-15 20:45:18

+1

你在最后一部分失去了我。 – dhg 2012-03-15 20:48:55