Подтвердить что ты не робот

Что означает как операторы *, так и (*) в рубине?

Я только что представил себя в Ruby splat oprator. И я много играл с ним. но приведенный ниже эксперимент каким-то образом заставил меня подумайте об этом дважды:)

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>'

Да, ошибка очевидна, так как я использовал более 1 оператора *(splat) в том же списке аргументов.

Теперь я попытался сыграть с ним.

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

Аааа! здесь он работает. Но не мог понять, почему так?

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

Из приведенного выше примера кажется, что он пропускает элементы массива.

Вопросы:

  • (a) что вызывается оператор (*)?

  • (b) когда я использовал в splat (*) в строке l1,*,l2 = *langs, он потребляет все элементы - "csharp", "ruby". Есть ли способ увидеть, что * потребляет там технически? Очевидно, что я связываюсь с использованием, если l1,*,l2 = *langs не l1,l*,l2 = *langs.

4b9b3361

Ответ 1

Это связано с как скобки работают с параллельным назначением, как объясняется Matz.

Например:

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

Отличается от:

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

В принципе, в скобках говорится: присвойте элементу правой руки этот индекс переменным в parens. Таким образом, 2 присваивается b, и ничего не осталось в индексе 1 для назначения c. Аналогично, (*) возьмет только элемент в заданном индексе и распределит его.

# 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 * are interpreted to mean 'take all elements at index 1,
# then again at index 2'
a, (*), (*), c = 1, 2, 3, 4

Обычно оператор * используется при объединении с переменной как *foo - но если нет, он будет удерживать свое место и принимать назначения элементов, как если бы они были переменной (по существу отбрасывая их)

Ответ 2

Подумайте об этом так: скобки сами по себе (игнорируя имя переменной или оператор splat) обращаются к одному элементу из массива:

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

Если бы это был массив массивов, было бы разумнее использовать скобки:

>> 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"

Следовательно, (*) принимает один элемент из массива и присваивает ему знак. Скобки сами берут элемент SINGLE, тогда splat принимает этот единственный элемент и "разбивает" его.

Следует отметить, что при выполнении присвоения переменной переменной из массива на стороне массива нет необходимости:

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

Ответ 3

(*) действительно просто читает один элемент с правой стороны. Рассмотрим этот пример, который имеет пятый элемент в массиве langs:

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

Итак, когда вы используете обычный знак, вы получаете:

l1,*,l2 = langs

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

в отличие от вашего примера с круглыми скобками:

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

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

Я хочу упомянуть, что для этого случая вы обычно использовали бы _ для присвоения средним значениям "ничего" (что эквивалентно последнему примеру):

l1,_,_,l2 = langs

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

Если вы хотите увидеть, что находится внутри средних значений, вы можете явно присвоить значения таким переменным:

l1,*m,l2 = *langs

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

или с другим примером:

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

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

Поэтому я надеюсь, что это ясно, что (*) не является оператором сам по себе, но на самом деле является просто символом в круглых скобках и поэтому не имеет собственного имени.