2010-06-22 13 views
17

Qualcuno sa se qualcosa di simile è possibile in Scala:E 'possibile per un valore di argomento opzionale per dipende da un altro argomento a Scala

case class Thing(property:String) 

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

Il codice di cui sopra non può essere compilato; dando l'errore error: not found: value thing a thing.property

Di seguito le proponiamo il comportamento previsto:

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

mi rendo conto che potrei fare la prop argomento un Option[String] e fare il check-nella definizione della funzione, ma mi chiedevo se ci fosse un modo per aggirarlo con il nuovo supporto per gli argomenti named/default in 2.8.0.

risposta

20

sì, è possibile, in Scala 2.8. Ecco una citazione dal documento "Named and Default Arguments in Scala 2.8" disegno:

Dal momento che il campo di applicazione di un parametro si estende su tutti gli elenchi successivi parametri (e il corpo del metodo), di default espressioni possono dipendere da parametri di precedenti liste di parametri (ma non su altri parametri nella stessa lista di parametri ). Si noti che quando si utilizza un valore predefinito che dipende dai parametri precedenti , vengono utilizzati gli argomenti effettivi , non gli argomenti predefiniti .

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

E un altro esempio:

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 

In base a questo, il codice può apparire come segue:

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

Grazie, questo è esattamente il genere di cosa che stavo cercando. –

+0

Prego :) –

0

Questo è esattamente ciò che è Option. È possibile utilizzare il metodo getOrElse prima della chiamata al metodo o all'interno del metodo 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 qui è qualcosa che si potrebbe fare con argomenti di default:

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 

Il comportamento previsto può essere realizzato con semplice sovraccarico. Avevo bisogno di mettere il metodo in un object perché sembra che il REPL non consente dichiarazioni di funzioni sovraccaricate diretti:

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

Ma penso che sia una cattiva pratica essere costretti a fornire 'Option' invece di argomenti normali. –

1

Un'altra soluzione semplice è solo quello di sovraccaricare il metodo:

case class Thing (property: String) 

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

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

Se non sbaglio, questo è il modo in cui C++ definisce parametri opzionali/predefiniti, giusto? –

+0

È da tempo che ho programmato in C++, ma puoi naturalmente fare la stessa cosa in C++ o anche in Java. – Jesper