2012-03-15 6 views
8

Je veux être en mesure de le faire:Scala - ajouter unapply à Int

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

Mais Int n'a pas une méthode unapply.

J'ai trouvé this answer qui donne des instructions sur la façon d'ajouter implicitement une méthode à un objet existant, donc je l'ai essayé. La solution qu'ils ont donné fonctionne, mais malheureusement pas pour le filtrage. Voici ce que j'ai:

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 

Ces cas de test sont tous très bien:

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

Mais celui que je veux échoue:

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 les travaux de conversion implicites et le modèle correspondant à unapply fonctionne, pourquoi Scala ne met-il pas ces deux choses ensemble pour un appariement de formes implicite?

Répondre

8

edit Donc, mon raisonnement original n'était pas bon. La vraie raison est de Section 8.1.8 of the Scala language spec

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

C'est l'objet d'extraction doit être stable, et une conversion implicite est pas stable. Aucune explication n'est donnée pour expliquer pourquoi l'extracteur doit être stable; Je pense qu'il est parce que Scala ne veut pas traiter l'extracteur comme une expression parce que cela pourrait rapidement devenir ambiguë:

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

Maintenant, ce qui est le constructeur et qui sont les variables de modèle?

Heureusement, vous pouvez le faire et il fonctionne très bien (même si, comme vous avez dit, introduit d'autres problèmes):

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

val Int(i) = "5" 

puisque le type Int et l'objet Int dans différents namespaces.

+0

Ha! Votre solution proposée est ce que j'utilise actuellement. Je ne suis pas entièrement satisfait car cela nécessite deux espaces de noms différents, ce qui signifie que je ne peux pas avoir 'Int.MaxValue' et' val Int (i) = "5" 'au même endroit. – dhg

+0

@dhg True. Et maintenant que je pense plus à ce sujet, je pense que le raisonnement dans ma réponse n'est pas tout à fait correct. La vraie raison est que les expressions de modèle ne peuvent pas être comme des expressions régulières parce que Scala doit identifier quelles choses sont des constructeurs et quelles sont les variables ... – Owen

+1

Vous m'avez perdu sur cette dernière partie. – dhg