2012-03-15 10 views
8

Quiero ser capaz de hacer esto:Scala - añadir a cancelar la aplicación Int

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

Pero Int no tiene un método unapply.

Encontré this answer que da instrucciones sobre cómo agregar implícitamente un método a un objeto existente, así que lo probé. La solución que dieron funciona, pero desafortunadamente no para la coincidencia de patrones. Aquí es lo que tengo:

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 

Estos casos de prueba son todos muy bien:

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

Pero el que quiero falla:

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" 
     ^

Si las obras de conversión implícitas y coincidencia de patrones con unapply funciona, ¿por qué Scala no combina estas dos cosas para la coincidencia de patrones implícita?

Respuesta

8

edit Así que mi razonamiento original no era bueno. La verdadera razón es de Section 8.1.8 of the Scala language spec

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

Es decir, el objeto extractora tiene que ser estable, y una conversión implícita no es estable. No se explica por qué el extractor debe ser estable; Sospecho que es porque no quiere Scala para tratar el extractor como una expresión ya que podría convertirse rápidamente ambigua:

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

Ahora que es el constructor y que son las variables del patrón?

Afortunadamente, usted puede hacer esto y funciona muy bien (aunque, como te comento, introduce otros problemas):

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

val Int(i) = "5" 

ya que el tipo Int y el objeto Int se encuentran en diferentes espacios de nombres.

+0

¡Ja! Su solución propuesta es lo que estoy usando actualmente. No estoy del todo contento con él porque requiere tener dos espacios de nombres diferentes, lo que significa que no puedo tener 'Int.MaxValue' y' val Int (i) = "5" 'en el mismo lugar. – dhg

+0

@dhg Verdadero. Y ahora que lo pienso más, creo que el razonamiento en mi respuesta no es del todo correcto. La verdadera razón es que las expresiones de patrones no pueden ser como expresiones regulares porque Scala tiene que identificar qué cosas son constructores y qué cosas son variables ... – Owen

+1

Me perdiste en esa última parte. – dhg