2010-06-22 25 views
17

Est-ce que quelqu'un sait si quelque chose comme cela est possible dans Scala:Est-il possible pour une valeur d'argument optionnel à dépendre d'un autre argument Scala

case class Thing(property:String) 

def f(thing:Thing, prop:String = thing.property) = println(prop) 

Le code ci-dessus ne compile pas; donnant l'erreur error: not found: value thing à thing.property

Ce qui suit montre le comportement attendu:

f(Thing("abc"), "123") // prints "123" 
f(Thing("abc"))  // prints "abc" 

Je me rends compte que je pourrais faire valoir prop un Option[String] et faire la vérification dans la définition de la fonction, mais je me demandais s'il y avait un moyen de contourner avec le nouveau support d'argument named/default dans 2.8.0.

Répondre

20

Oui, il est possible à Scala 2.8. Voici une citation du document de conception "Named and Default Arguments in Scala 2.8":

Depuis la portée d'un paramètre étend sur toutes les listes de paramètres après (et le corps de la méthode), les expressions par défaut peuvent dépendre de paramètres des précédents listes de paramètres (mais pas sur les autres paramètres de la même liste de paramètres ). Notez que lorsque vous utilisez une valeur par défaut qui dépend des paramètres précédents , les arguments réels sont utilisés, pas les arguments par défaut .

def f(a: Int = 0)(b: Int = a + 1) = b // OK 

Et un autre exemple:

def f[T](a: Int = 1)(b: T = a + 1)(c: T = b) 
// generates: 
// def f$default$1[T]: Int = 1 
// def f$default$2[T](a: Int): Int = a + 1 
// def f$default$3[T](a: Int)(b: T): T = b 

D'après cela, votre code peut se présenter comme suit:

scala> case class Thing(property:String) 
defined class Thing 

scala> def f(thing:Thing)(prop:String = thing.property) = println(prop) 
f: (thing: Thing)(prop: String)Unit 

scala> f(Thing("abc"))("123") 
123 

scala> f(Thing("abc"))() 
abc 
+0

Merci, c'est exactement le genre de chose que je recherchais. –

+0

Vous êtes les bienvenus :) –

0

C'est exactement ce que Option est pour. Vous pouvez utiliser la méthode getOrElse avant l'appel de la méthode ou à l'intérieur de la méthode f.

scala> val abc = Some("abc") 
abc: Some[java.lang.String] = Some(abc) 

scala> val none: Option[String] = None 
none: Option[String] = None 

scala> println(abc getOrElse "123") 
abc 

scala> println(none getOrElse "123") 
123 

scala> def f(o: Option[String]) = println(o getOrElse "123") 
f: (o: Option[String])Unit 

scala> f(abc) 
abc 

scala> f(none) 
123 

Oh voici quelque chose que vous pouvez faire par des arguments par défaut:

scala> case class Thing(property: String = "123") 
defined class Thing 

scala> def f(t: Thing) = println(t.property) 
f: (t: Thing)Unit 

scala> f(Thing("abc")) 
abc 

scala> f(Thing()) 
123 

Le comportement attendu peut être réalisé avec une surcharge simple. Je avais besoin de mettre la méthode dans un object parce qu'il ressemble à la REPL ne permet pas des déclarations de fonction surchargée directe:

scala> object O { 
     def overloaded(t:Thing) = println(t.property) 
     def overloaded(t:Thing,s:String) = println(s) 
     } 
defined module O 

scala> O.overloaded(Thing("abc"), "123") 
123 

scala> O.overloaded(Thing("abc")) 
abc 
+0

Mais je pense que c'est une mauvaise pratique d'être forcé de fournir 'Option' à la place des arguments normaux. –

1

Une autre solution simple est juste de surcharger la méthode:

case class Thing (property: String) 

def f(thing: Thing, prop: String) = println(prop) 

def f(thing: Thing) = f(thing, thing.property) 
+0

Si je ne me trompe pas, c'est ainsi que C++ définit les paramètres optionnels/par défaut, non? –

+0

Cela fait longtemps que j'ai programmé en C++, mais vous pouvez bien sûr faire la même chose en C++ ou en Java. – Jesper