Пометка неиспользуемой блок-переменной

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

{[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

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

Ответ 1

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

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

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

Очень мало случаев, когда вы хотите использовать звезду для игнорирования параметров. Например, если вы хотите использовать только последнее переменное количество параметров:

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

Ruby позволяет не указывать имя "остатка" параметров, но вы можете использовать _:

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

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

  • Ruby не будет жаловаться, если вы его не используете (если предупреждения включены)
  • Ruby позволит вам повторить его в списке аргументов.

Пример точки 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

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

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

Ответ 2

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

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

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

Ответ 3

Каковы различия между ними?

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

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

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

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

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

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

Ответ 4

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

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

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