2013-02-18 13 views
13

Mi sono appena presentato allo splat di Ruby. E ho giocato con lui in molti modi. ma l'esperimento di seguito in qualche modo mi ha fatto pensarci due volte :)Cosa significa sia gli operatori * che (*) in ruby?

langs = ["java", "csharp", "ruby", "haskell" ] 
# => ["java", "csharp", "ruby", "haskell"] 

l1,*,l2 = *langs 
# => ["java", "csharp", "ruby", "haskell"] 
l1 
# => "java" 
l2 
# => "haskell" 

l1,*,*,l2 = *langs 
SyntaxError: (irb):27: syntax error, unexpected tSTAR 
l1,*,*,l2 = *langs 
    ^
    from /usr/bin/irb:12:in `<main>' 

Sì, l'errore è evidente, come ho usato più di 1 *(splat) operatori nella stessa lista degli argomenti.

Ora ho provato a giocare con esso.

l1,(*),(*),l2 = *langs 
# => ["java", "csharp", "ruby", "haskell"] 

Ahh! qui funziona. Ma non riuscivo a capire perché?

l1 
# => "java" 
l2 
# => "haskell" 
l1,(*),l2 = *langs 
# => ["java", "csharp", "ruby", "haskell"] 
l1 
# => "java" 
l2 
# => "ruby" 

Dall'esempio precedente sembra che stia saltando gli elementi dell'array.

Le domande sono:

  • (a) quello che l'operatore (*) si chiama?

  • (b) quando ho usato in splat (*) nella riga l1,*,l2 = *langs consuma tutti gli elementi - "csharp", "ruby". C'è un modo per vedere cosa consuma tecnicamente lo *? Ovviamente sto chiamando con l'uso se l1,*,l2 = *langs non da l1,l*,l2 = *langs.

+0

Una domanda molto ben fatta. Non so nulla di rubino, ma in superficie sembra essere in qualche modo un accessorio di tipo "jolly", se questo ha senso. Presumo che consuma più elementi possibile prima che il prossimo token venga analizzato. –

+0

@ RichardJ.RossIII Grazie per mostrare il vostro interesse. Sono a conoscenza di '*' ma non di (*). :) –

+0

Qualcuno potrebbe suggerirmi quando tutte le risposte sono ** OK **, allora cosa fare? come non posso accettare più di uno. –

risposta

9

Ciò è dovuto a how parentheses work with parallel assignment come spiegato da Matz.

Ad esempio:

a, b, c = *[1, 2, 3] 
a => 1 
b => 2 
c => 3 

è diverso:

a, (b, c) = *[1, 2, 3] 
a => 1 
b => 2 
c => nil 

Fondamentalmente, la parentesi dire: assegnare l'elemento destro in questo indice alle variabili nelle parentesi. Quindi 2 è assegnato a b, con nulla lasciato all'indice 1 da assegnare a c. Allo stesso modo, (*) prenderà solo l'elemento al dato indice e lo distribuirà.

# the * is interpreted to mean 'take all remaining elements' 
a, * = 1, 2, 3, 4 

# the * is interpreted to mean 'take all remaining elements except 
# the last element' 
a, *, c = 1, 2, 3, 4 

# incorrect syntax, can't splat more than once on all remaining 
# elements 
a, *, *, c = 1, 2, 3, 4 

# the * is interpreted to mean 'take all elements at index 1' 
a, (*), c = 1, 2, 3, 4 

# the *'s are interpreted to mean 'take all elements at index 1, 
# then again at index 2' 
a, (*), (*), c = 1, 2, 3, 4 

Tipicamente, l'operatore * viene utilizzato in combinazione con una variabile come *foo - ma se non si terrà il suo posto e prendere assegnazioni all'elemento come se fosse una variabile (essenzialmente scartarli)

+0

Humm, so che è un compito parallelo. Ma come '*' funziona senza oggetti o post variabili. Cos'è '(*)'? –

+2

L'operatore splat è lo stesso con o senza la parentesi. Il() dice a Ruby di scegliere un singolo elemento dal lato destro e assegnarlo al contenuto delle parentesi. Quando * è usato sul lato sinistro di un compito senza una variabile, è semplicemente un segnaposto per spostare l'assegnazione agli elementi seguenti senza assegnare effettivamente gli elementi "splattati" a una variabile. Quindi, no, non si può dire dopo il fatto che è stato assegnato a '* o' (*) 'dal momento che non lo si persiste da qualche parte, ma piuttosto di usarlo come segnaposto. – PinnyM

+1

'a, * b, c = [1,2,3,4]' => 'a = 1; b = [2,3]; c = 4'. Senza una variabile con lo splat, assorbe semplicemente i valori e li elimina. 'a, *, c = [1,2,3,4]' => 'a = 1; c = 4' –

6

Riflessione in questo modo: la parentesi da soli (ignorando un nome variabile o operatore splat) accedono un singolo elemento dell'array:

l1, (),(), l2 = *['a', 'b', 'c', 'd'] 
^ ^^^
'a' 'b' 'c' 'd' 

Se fosse un array di array, avrebbe più senso uso parentesi:

>> l1,(l3, l4),(l5, l6),l2 = *['a', ['b', 'c'], ['d', 'e'], 'f'] 
=> ["a", ["b", "c"], ["d", "e"], "f"] 
>> l1 
=> "a" 
>> l3 
=> "b" 
>> l4 
=> "c" 
>> l5 
=> "d" 
>> l6 
=> "e" 
>> l2 
=> "f" 

Dunque la (*) sta prendendo un singolo elemento dalla matrice, e splat-assegnandogli.Le parentesi stesse prendono un elemento SINGLE, lo splat quindi prende quel singolo elemento e lo "splats".

È bene notare che quando si esegue l'assegnamento multi-variabile da una matrice, il simbolo non è necessario sul lato matrice:

>> a,b,c = ['a', 'b', 'c'] 
=> ["a", "b", "c"] 
>> a 
=> "a" 
>> b 
=> "b" 
>> c 
=> "c" 
+0

Impossibile capire 'lo splat prende quindi quel singolo elemento e lo" splats ". Dove l'operatore di splat nel tuo esempio? Stai parlando del lato destro? –

+0

Il mio esempio non aveva un operatore splat perché non ritenevo necessario uno per illustrare il punto. La * parentesi * prende il singolo elemento 'b' dal primo esempio, o '['b', 'c']' dal secondo. Uno splat all'interno di quelle parentesi (invece delle variabili) opererebbe esclusivamente su quel 'b' o' ['b', 'c'] '- NOT su qualsiasi parte del resto dell'array. – nzifnab

6

(*) realtà solo legge un elemento dal lato destro. Considerate questo esempio, che ha un quinto elemento nella langs matrice:

langs = ["java", "csharp", "ruby", "haskell", "python" ] 

Così, quando si utilizza un simbolo normale, si ottiene:

l1,*,l2 = langs 

l1 #=> "java" 
l2 #=> "python" 

in contrasto con il tuo esempio con le parentesi:

Voglio menzionare che, in questo caso, normalmente si utilizzerà _ per assegnare i valori medi a "niente" (equivalente all'ultimo esempio):

l1,_,_,l2 = langs 

l1 #=> "java" 
l2 #=> "haskell" 

Se volete vedere quello che ha finito per essere all'interno dei valori medi, è possibile assegnare in modo esplicito i valori alle variabili in questo modo:

l1,*m,l2 = *langs 

l1 #=> "java" 
l2 #=> "python" 
m #=> ["csharp","ruby","haskell"] 

o con l'altro esempio:

l1,(*m1),(*m2),l2 = langs 

l1 #=> "java" 
l2 #=> "haskell" 
m1 #=> ["csharp"] 
m2 #=> ["ruby"] 

Quindi spero che questo chiarisca che (*) non è un operatore a sé stante, ma in realtà solo uno splat tra parentesi e quindi non ha un proprio nome.

+0

un punto qui - '*' consuma tutto il resto dal lato destro. Quello è buono. Ma dove li tiene dopo averli consumati? con '* a' - possiamo ottenere quei valori, ma senza questa variabile post - nessuna possibilità di accedere a quei valori di riposo? Dopo tutto, una cosa è vera che li ha consumati, quindi ** dove sono **? : D –

+1

Attenzione: lo splat è molto avido e ha sempre fame. Nessuno ha mai visto un valore tornare da esso! –