Alcuni luoghi (ad esempio Play Form.bindFromRequest
) utilizzano un elenco di parametri vuoto prima dell'elenco dei parametri impliciti. Perché? IMHO, ha lo svantaggio di richiedere parentesi aggiuntive quando il parametro viene passato esplicitamente come in form.bindFromRequest()(request)
. Non sai quale sia il vantaggio allora?Scala: perché una lista di argomenti vuota viene dichiarata prima dell'elenco implicito
risposta
A def
con un elenco di parametri ha un tipo diverso da quello senza elenco di parametri. Questo non ha importanza nell'invocazione diretta, ma se si passa quel metodo come argomento ad un altro metodo, lo fa.
Nel esempio, se si definisce il metodo in questo modo:
def func1 = { println("Hello"); 1 }
Non è possibile passare a questo metodo:
def consume(f:() => Double) = // ...
come è tipo è semplicemente doppio, anche se un molto pigro uno. D'altra parte questa funzione funzionerà bene:
def func2() = { println("Hello"); 2 }
Non sto dicendo che questo è il motivo esplicito perché l'hanno fatto, ma se avevano un motivo reale, essa sarà quasi certamente legato a digitare.
EDIT:
La differenza tra loro in termini pratici si tratta per lo più verso il basso per cui possono essere utilizzati.
L'elemento call-by-value può essere utilizzato in un elenco di parametri solo per una funzione/metodo (afaik). Poiché può essere passato solo in un elenco di parametri, non è possibile memorizzarlo in una variabile e utilizzarlo in più posizioni (senza modificarlo in un'istanza esplicita di T
).
E come si può vedere qui, non sono intercambiabili per sé:
scala> def f(s: => String) { println(s) }
f: (s: => String)Unit
scala> def s1 =() => { "Hello" }
s1:() => String
scala> f(s1)
<console>:10: error: type mismatch;
found :() => String
required: String
f(s1)
^
Quindi immagino ho voluto memorizzare una serie di callback che gli utenti passano a me .. non posso usare => T
qui :
scala> val a: Array[=> Int] = Array()
<console>:1: error: identifier expected but '=>' found.
val a: Array[=> Int] = Array()
^
scala> val a: Array[() => Int] = Array()
a: Array[() => Int] = Array()
Quindi, se voglio per memorizzare tali articoli, e passarle intorno internamente, utilizzando => T
(e tenendolo pigramente valutata) non è un'opzione.
Penso che sia meglio non pensare allo =>
in => T
e () => T
come a dire la stessa cosa. Spero che questo aiuti un po '.
Vero, ma è possibile definire consumare come 'def consumare (f: => Double)' che è equivalente al tuo consumo, vero? –
Questo è un parametro pass by name non una funzione1. –
Mi spiace, intendo Function0. –
Non sei autorizzato a scriverlo senza uno, no? IMO che porterebbe a comportamenti molto confusionari grazie al principio di accesso uniforme - quello che sembrava un semplice accesso alla proprietà potrebbe essere fare cose arbitrariamente complesse con impliciti. – lmm
@lmm È possibile scrivere questo stesso metodo senza l'elenco dei parametri vuoto (o così si dice un tentativo superficiale nel REPL). I costruttori di classi ricevono automaticamente una lista di parametri vuota se sono definiti solo gli impliciti, ma i metodi sembrano funzionare senza di essi. Se sia una buona idea farlo, non lo so. –
Si noti inoltre che sebbene il metodo sia definito con un elenco di argomenti vuoto prima degli argomenti impliciti, è comunque possibile richiamarlo come 'form.bindFromRequest' senza alcun avvertimento dal compilatore.Quindi molto probabilmente è meglio seguire la convenzione quando si definisce la funzione, ma quando si invoca si possono omettere le parentesi (se il metodo non ha effetti collaterali, perché in base alle guide di stile è meglio mantenere le parentesi per rendere chiaro che un effetto collaterale sta accadendo chiamando questa funzione). –