Пометка неиспользуемой блочной переменной - PullRequest
11 голосов
/ 31 декабря 2011

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

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

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

Ответы [ 4 ]

31 голосов
/ 01 января 2012

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

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

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

  1. Ruby не будет жаловаться, если вы его не используете (если включены предупреждения)
  2. 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
1 голос
/ 31 декабря 2011

Чем они отличаются?

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

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

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

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

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

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

1 голос
/ 31 декабря 2011

IMO практика делает код менее читабельным и менее очевидным.

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

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

1 голос
/ 31 декабря 2011

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

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

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

...