2012-08-10 18 views
10

Sono un principiante professionista in Scala e ho visto una sintassi diversa per chiamare un metodo. Alcuni sono bello, come ignorando la parentesi di un metodo senza parametri, o ignorare il punto come inScala - sintassi della chiamata di metodo

1 to 10 

ma alcuni veramente mi puzzle. per esempio:

breakable { ... } 

questo è semplicemente un metodo di chiamata giusto? Posso farlo anche per più di un parametro o un parametro che non è una funzione senza parametri?

Grazie

+2

sì, è una chiusura. stai passando un blocco di codice in un metodo. Nota che in Scala puoi usare {} al posto di() per passare il parametro singolo ai metodi – aishwarya

+0

Cosa ti infastidisce qui? È il blocco di codice (la parte '{...}') dopo il nome del metodo o il fatto che non facciamo il prefisso del metodo con un nome di oggetto/classe? – Nicolas

risposta

22

Ci sono due modi standard di metodi di chiamata:

obj.method(params) // dot notation 
obj method (params) // operator notation 

quanto sopra può essere modificato nei modi seguenti:

  1. Se params è un parametro singolo, è possibile sostituire () con {}.
  2. Se è un singolo parametro e si utilizza la notazione dell'operatore, è possibile rilasciare la parentesi.
  3. Se method non accetta parametri, è possibile eliminare (params) (ovvero, rilasciare lo () vuoto).
  4. Se method termina con :, allora si lega effettivamente a destra nella notazione dell'operatore. Cioè, (params) method_: obj equivale a obj.method_:(params).
  5. In entrambi i casi, gli spazi sono opzionali a condizione che gli identificatori possano essere distinti. Pertanto, è possibile aggiungere spazi alla notazione punti, ad esempio obj . method (params) o scrivere .method(params) nella riga successiva, come spesso accade con il concatenamento delle chiamate, nonché rimuovere gli spazi dalla notazione dell'operatore, come in a+b.

C'è anche qualcosa con l'inferenza della tupla, ma cerco di evitarlo, quindi non sono sicuro delle regole esatte.

Nessuno di questi spiegherà comunque l'esempio di cui si è confusi.Prima di spiegare che, però, mi piacerebbe mostrare alcuni zuccheri sintattici che possono anche essere utilizzati per chiamare i metodi:

obj(params) // equivalent to obj.apply(params) 
obj.x = y // equivalent to obj.x_=(y), if obj.x also exists 
obj(x) = y // equivalent to obj.update(x, y) 
obj op= y // equivalent to obj = obj op y, if op is symbolic 
~obj  // equivalent to obj.unary_~; also for !, + and -, but no other symbol 

Ok, ora per l'esempio che ha dato. Si può importare membri di valori stabili. Java può farlo per i metodi statici con la sua importazione statica, ma Scala ha un meccanismo più generale: l'importazione da pacchetti, oggetti o istanze comuni non è diversa: porta sia membri di tipo che membri di valore. I metodi rientrano in quest'ultima categoria.

Quindi, immagina di avere val a = 2 e lo fai import a._. Ciò porterà tutti i metodi Int, quindi puoi chiamarli direttamente. Non si può fare +(2), perché sarebbe interpretato come una chiamata a unary_+, ma si potrebbe chiamare *(4), ad esempio:

scala> val a = 2 
a: Int = 2 

scala> import a._ 
import a._ 

scala> *(4) 
res16: Int = 8 

Ora, qui è la regola. È possibile chiamare

method(params) 

Se:

  1. method è stato importato in ambito.
  2. si mantiene la parentesi (anche se c'è un solo parametro)

Nota che c'è un problema di precedenza pure. Se si scrive obj method(params), Scala presumerà che method appartiene a obj, anche se è stato importato nell'ambito.

+0

Ottima risposta. Ho appena avuto una domanda sul tuo punto numero 1, sull'essere in grado di chiamare un metodo con {} notation anziché(). C'è qualche ragione specifica per cui questa sintassi è disponibile? Questa sintassi sembra essere comunemente usata in molti framework e nei loro esempi documentati. Mi chiedo se questa particolare sintassi sia supportata per una ragione funzionale e molto specifica. Viene generalmente utilizzato quando si passano le chiusure come argomenti per una funzione? Mi piacerebbe capire le sue radici in modo che io possa coglierlo e ragionarlo con chiarezza. Grazie. – HiChews123

+2

@ acspd7 Bene, '()' e '{}' hanno significati diversi all'interno di un'espressione _. Cioè, '2 * (3 + 4)' e '2 * {3 + 4}' hanno lo stesso risultato, ma sono cose diverse. Puoi mettere espressioni solo all'interno di una parentesi, mentre tu metti _definitions_ e _statements_ all'interno di parentesi graffe, e il valore dell'ultima istruzione è il valore di espressione di essa (le parentesi graffe sono esse stesse un'espressione). La ragione per cui 'f (...)' può essere sostituita con 'f {...}' è così che le persone non devono scrivere 'f ({...})'. Ciò consente alle persone di scrivere strutture di controllo "utente" che sembrano native. –

15

Se desugar questo avremo:

breakable({ ... }) 

questo corrisponde firma

breakable: (op: ⇒ Unit): Unit 

e usa così chiamato Call-by-name argomenti (si potrebbe pensare di questo come passare un blocco di codice come argomento)

Più sopra scala consente di scrivere questo:

scala> def foo (op1: => Unit)(op2: => Unit) = {op1;op2;} 
foo: (op1: => Unit)(op2: => Unit)Unit 

scala> foo { println(1) } { println(2) } 
1 
2 

Sopra è l'esempio della funzione curry