Domanda Cosa significa sia gli operatori * che (*) nel rubino?


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 pensaci due volte :)

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 è ovvio, poiché ho usato più di 1 *(splat) operatori nella stessa lista di argomenti.

Ora ho provato a giocarci.

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 degli elementi dell'array.

Le domande sono:


13
2018-02-18 20:10


origine


risposte:


Questo è dovuto a come le parentesi funzionano con l'assegnazione parallela come spiegato da Matz.

Per esempio:

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

È diverso da:

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

Fondamentalmente, le parentesi dicono: assegna l'elemento della mano destra a questo indice alle variabili nei parens. Quindi 2 è assegnato a b, con niente lasciato all'indice 1 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

In genere, il * l'operatore è usato in combinazione con una variabile come *foo - ma se no, manterrà il suo posto e prenderà i compiti degli elementi come se fosse una variabile (essenzialmente scartandoli)


9
2018-02-18 20:28



Pensala in questo modo: le parentesi da sole (ignorando un nome di variabile o un operatore di splat) stanno accedendo a un singolo elemento dall'array:

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

Se fosse una matrice di matrici, avrebbe più senso usare la 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"

Pertanto (*) sta prendendo un singolo elemento dall'array e lo assegna a splat. Le parentesi stesse prendono un elemento SINGLE, lo splat prende quindi quel singolo elemento e lo "splats".

È bene notare che quando si esegue l'assegnazione multi-variabile da un array, lo splat non è necessario sul lato dell'array:

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

6
2018-02-18 20:49



(*) davvero solo legge uno elemento dal lato destro. Considera questo esempio, che ha un quinto elemento nel langs array:

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

Quindi, quando usi uno splat normale, ottieni:

l1,*,l2 = langs

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

in contrasto con il tuo esempio con le parentesi:

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

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

Voglio menzionare, però, che per questo caso useresti normalmente _ per assegnare i valori medi a "nulla" (equivalente all'ultimo esempio):

l1,_,_,l2 = langs

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

Se vuoi vedere cosa è finito all'interno dei valori medi, puoi assegnare esplicitamente 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 lo chiarisca (*) non è un operatore a sé stante, ma in realtà solo uno splat tra parentesi e quindi non ha un proprio nome.


6
2018-02-18 21:16