2010-06-22 13 views
17

¿Alguien sabe si algo como esto es posible en Scala:¿Es posible que un valor de argumento opcional que depende de otro argumento en Scala

case class Thing(property:String) 

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

El código anterior no compila; dando el error error: not found: value thing en thing.property

A continuación se muestra el comportamiento esperado:

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

Me di cuenta que podía hacer el prop argumento de una Option[String] y hacer la verificación en la definición de la función, pero me preguntaba si había una forma de evitarlo con el nuevo soporte de argumento nombrado/predeterminado en 2.8.0.

Respuesta

20

sí, es posible en Scala 2.8. Aquí está una cita del documento "Named and Default Arguments in Scala 2.8" diseño:

Dado que el alcance de un parámetro se extiende sobre todas las listas de parámetros posterior (y el cuerpo del método), por defecto expresiones pueden depender de parámetros de precedente listas de parámetros (pero no en otros parámetros en la misma lista de parámetros ). Tenga en cuenta que cuando se utiliza un valor predeterminado que depende de parámetros anteriores, se utilizan los argumentos reales, no los argumentos predeterminados .

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

Y otro ejemplo:

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 

De acuerdo con esto, el código puede ser similar al siguiente:

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

Gracias, eso es exactamente el tipo de cosa que estaba buscando. –

+0

De nada :) –

0

Esto es exactamente lo que Option es para. Puede utilizar el método getOrElse antes de la llamada al método o dentro del método 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, aquí es algo que podría hacer a través de los argumentos por defecto:

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 

El comportamiento esperado se puede lograr con una simple sobrecarga. Necesitaba poner el método en un object porque parece que el REPL no permite la declaración de funciones sobrecargadas directos:

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

Pero creo que es una mala práctica estar obligado a proporcionar 'Option' en lugar de argumentos normales. –

1

Otra solución simple es sólo para sobrecargar el método:

case class Thing (property: String) 

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

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

Si no me equivoco, así es como C++ define los parámetros opcionales/predeterminados, ¿verdad? –

+0

Hace mucho tiempo que programé en C++, pero por supuesto puedes hacer lo mismo en C++ o también en Java. – Jesper

Cuestiones relacionadas