Definizioni di classe:
val
oppure var
può essere omesso dai parametri di classe che renderanno il parametro privato.
L'aggiunta di var o val renderà pubblico (ovvero, vengono generati metodi di accesso e mutatori).
{}
può essere omesso se la classe non ha un corpo, ovvero
class EmptyClass
Istanziazione della classe:
I parametri generici possono essere omessi se possono essere dedotti dal compilatore. Tuttavia, tieni presente che se i tuoi tipi non corrispondono, il parametro del tipo viene sempre dedotto in modo che corrisponda. Quindi senza specificare il tipo, potresti non ottenere ciò che ti aspetti, cioè dato
class D[T](val x:T, val y:T);
Questo ti darà un errore di tipo (Int trovato, stringa prevista)
var zz = new D[String]("Hi1", 1) // type error
Mentre questo funziona bene:
var z = new D("Hi1", 1)
== D{def x: Any; def y: Any}
Perché il parametro di tipo, T, viene dedotto come il supertipo meno comune dei due: Any.
Definizioni di funzione:
=
può essere eliminato se la funzione restituisce Unit (niente).
{}
per il corpo della funzione può essere eliminato se la funzione è una singola istruzione, ma solo se l'istruzione restituisce un valore (è necessario il =
segno), ovvero,
def returnAString = "Hi!"
ma questo non funziona:
def returnAString "Hi!" // Compile error - '=' expected but string literal found."
Il tipo restituito della funzione può essere omesso se può essere dedotto (un metodo ricorsivo deve avere il tipo restituito specificato).
()
può essere eliminato se la funzione non accetta alcun argomento, ovvero
def endOfString {
return "myDog".substring(2,1)
}
che per convenzione è riservato ai metodi che non hanno effetti collaterali - ne parleremo più avanti.
()
non è effettivamente scartato di per sé quando si definisce un parametro di passaggio per nome , ma in realtà è una notazione abbastanza semanticamente diversa, cioè
def myOp(passByNameString: => String)
Dice che myOp accetta un parametro pass-by-name, che si traduce in una stringa (cioè, può essere un blocco di codice che restituisce una stringa) al contrario dei parametri della funzione,
def myOp(functionParam: () => String)
che dice che myOp
accetta una funzione che ha zero parametri e restituisce una stringa.
(Intendiamoci, i parametri pass-by-name vengono compilati in funzioni; rende semplicemente più gradevole la sintassi.)
()
può essere rilasciato nella definizione del parametro della funzione se la funzione accetta solo un argomento, ad esempio:
def myOp2(passByNameString:(Int) => String) { .. } // - You can drop the ()
def myOp2(passByNameString:Int => String) { .. }
Ma se richiede più di un argomento, è necessario includere il ():
def myOp2(passByNameString:(Int, String) => String) { .. }
dichiarazioni:
.
può essere abbandonato per usare la notazione dell'operatore, che può essere usata solo per gli operatori infisso (operatori di metodi che accettano argomenti). Vedi la risposta di Daniel per maggiori informazioni.
.
può anche essere rilasciato per la coda dell'elenco delle funzioni di suffisso
()
può essere rilasciato per gli operatori postfix list.tail
()
non può essere utilizzato con metodi definiti come:
def aMethod = "hi!" // Missing () on method definition
aMethod // Works
aMethod() // Compile error when calling method
Perché questa notazione è riservata per convenzione ai metodi che non hanno effetti collaterali, come List # tail (ovvero, l'invocazione di una funzione senza effetti collaterali significa che la funzione non ha alcun effetto osservabile, ad eccezione del suo valore restituito).
()
può essere eliminato per la notazione dell'operatore quando si passa un singolo argomento
()
potrebbe essere richiesto di utilizzare operatori postfissa che non sono alla fine di un'istruzione
()
può essere richiesto di designare istruzioni annidate, estremità di funzioni anonime o per operatori che accettano più di un parametro
Quando si chiama una funzione che accetta una funzione, non è possibile omettere () dalla definizione della funzione interna, ad esempio:
def myOp3(paramFunc0:() => String) {
println(paramFunc0)
}
myOp3(() => "myop3") // Works
myOp3(=> "myop3") // Doesn't work
Quando si chiama una funzione che accetta un parametro per nome, non è possibile specificare l'argomento come una funzione anonima senza parametri. Ad esempio, dato:
def myOp2(passByNameString:Int => String) {
println(passByNameString)
}
Devi chiamarlo come:
myOp("myop3")
o
myOp({
val source = sourceProvider.source
val p = myObject.findNameFromSource(source)
p
})
ma no:
myOp(() => "myop3") // Doesn't work
IMO, un uso eccessivo dei tipi di restituzione della caduta può essere dannoso per il riutilizzo del codice. Basta guardare le specifiche per un buon esempio di leggibilità ridotta a causa della mancanza di informazioni esplicite nel codice. Il numero di livelli di riferimento indiretto per capire effettivamente quale sia il tipo di variabile può essere pazzo. Si spera che strumenti migliori possano evitare questo problema e mantenere il nostro codice conciso.
(OK, nel tentativo di compilare una risposta più completa e concisa (se ho perso qualcosa o ho ottenuto qualcosa di sbagliato / impreciso per favore commenta), ho aggiunto all'inizio della risposta. Tieni presente che questa non è una lingua specifica, quindi non sto cercando di renderlo esattamente accademicamente corretto, solo più simile a una scheda di riferimento.)