2011-12-31 4 views
7

Когда есть блок или локальная переменная, которая не используется, иногда люди отмечают ее *, а иногда и с _.Маркировка неиспользуемой переменной блока

{[1, 2] => 3, [4, 5] => 6}.each{|(x, *), *| p x} 

{[1, 2] => 3, [4, 5] => 6}.each{|(x, _), _| p x} 

{[1, 2, 3], [4, 5, 6]}.each{|*, x, *| p x} 

{[1, 2, 3], [4, 5, 6]}.each{|_, x, _| p x} 

def (x, *), *; p x; end 

def (x, _), _; p x; end 

def *, x, *; p x; end 

def _, x, _; p x; end 

Каковы различия между ними и когда следует использовать их? Когда нужно отметить несколько переменных как неиспользуемых, как в приведенных выше примерах, лучше?

ответ

26

A * означает «все остальные параметры». _ - это просто другое имя переменной, хотя оно немного особенное. Таким образом, они отличаются, например, следующее не имеет смысла:

[[1, 2, 3], [4, 5, 6]].each{|*, x, *| p x} # Syntax error 

В самом деле, как рубин должен знать, если первая звезда должна получить 0, 1 или 2 значений (и наоборот)?

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

Рубин позволяет не дать название «остальное» параметров, но вы можете использовать _:

[[1], [2, 3], [4, 5, 6]].each{|*_, last| p last} # => prints 1, 3 and 6 

как правило, количество параметров, как известно, и ваш лучший выбор использовать _:

[[1, 2, 3], [4, 5, 6]].each{|_, mid, _| p mid} # prints 2 and 5 

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

[[1, 2, 3], [4, 5, 6]].each{|_, mid, | p mid} # prints 2 and 5 

Теперь _ является обозначается имя переменной, чтобы использовать, когда вы не хотите использовать значение. Это специальное имя переменной по двум причинам:

  1. Рубин не будет жаловаться, если вы не используете его (если предупреждения о)
  2. рубин позволит вам повторить его в списке аргументов.

Пример пункта 1:

> ruby -w -e "def foo; x = 42; end; foo" 
-e:1: warning: assigned but unused variable - x 

> ruby -w -e "def foo; _ = 42; end; foo" 
no warning 

Пример пункта 2:

[[1, 2, 3], [4, 5, 6]].each{|unused, mid, unused| p mid} 
# => SyntaxError: (irb):23: duplicated argument name 

[[1, 2, 3], [4, 5, 6]].each{|_, mid, _| p mid} 
# => prints 2 and 5 

Наконец, как @DigitalRoss нот, _ держит последний результат в irb

Update: В Ruby 2.0 вы можете использовать любую переменную, начиная с _ означает, что он не используется. Таким образом, имя переменной может быть более явным в отношении того, что игнорируется:

_scheme, _domain, port, _url = parse_some_url 
# ... do something with port 
+0

Спасибо за подробный ответ.Этот ответ содержит всю информацию, которую я хотел. – sawa

1

Я думаю, что это в основном стилистика и выбор программиста. Использование * имеет больше смысла для меня в Ruby, потому что его целью является накопление всех параметров, переданных с этой позиции вперед. _ - это рудиментарная переменная, которая редко видит использование в Ruby, и я слышал комментарии, которые нужно уйти. Поэтому, если бы я использовал, я бы использовал *.

НЕКОТОРЫЕ компании могут определить его в своем документе о стиле программирования, если они есть, но я сомневаюсь, что он стоит большую часть времени, потому что это переменная отбрасывания. Я развиваюсь профессионально уже более 20 лет и никогда не видел ничего, определяющего название выброса.

Лично я не беспокоюсь об этом, и меня больше беспокоит использование однобуквенных переменных. Вместо этого я использовал бы unused или void или blackhole для этой цели.

+3

'_' * не * уходит и имеет конкретное обращение, см. Мой ответ. Более того, запуск Ruby in warn может дать вам предупреждения при использовании 'unused' или simial, но не с' _'; см. мой ответ too ;-) –

1

В чем разница между ними?

В случае _ создается локальная переменная _. Это похоже на использование x, но по-разному.

В * случае назначение выражения для * создает [expression]. Я не совсем уверен, что он полезен, поскольку он, похоже, не делает ничего, что окружает выражение с помощью скобок.

Когда следует использовать какой?

Во втором случае у вас не получается создать дополнительный символ, но для интерпретатора это выглядит немного больше. Кроме того, очевидно, что вы никогда не будете использовать этот результат, тогда как с _ нужно было бы прочитать цикл, чтобы узнать, используется ли он.

Но я предсказываю, что качество вашего кода будет зависеть от других вещей, чем трюк, который вы используете, чтобы избавиться от неиспользуемых параметров блока. У * действительно есть какой-то неясный крутой фактор, который мне нравится.

Примечание: При проведении экспериментов следует помнить, что в irb _ содержит значение последнего выражения.

+0

Вы имели в виду '**' case, или '*'? Я имел в виду '*', но они разные? Я знаю использование '*' как создание массива при префиксе к имени переменной, но является ли изолированное использование '*' одинаковым? И в основной среде, если я набираю '* = ['a']', он возвращает '['a']'. Что это значит? – sawa

1

ИМО практика делает код менее читаемым и менее очевидным.

В частности, в методах API, использующих блоки, может быть неясно, чего ожидает блок. Это сознательно удаляет информацию из источника, что затрудняет техническое обслуживание и модификацию.

Я предпочел бы, чтобы переменные были названы соответственно; в коротком блоке будет очевидно, что он не используется. В более длинных блоках, если неиспользование замечательно, комментарий может объяснить причину.

Смежные вопросы