Может кто-нибудь объяснить использование Ruby символов канала в блоке? - PullRequest
31 голосов
/ 22 ноября 2010

Может кто-нибудь объяснить мне, как Руби использует символы канала в блоке? Я понимаю, что он содержит имя переменной, которой будут назначены данные при ее итерации. Но как это называется? Может ли быть более одной переменной внутри труб? Что-нибудь еще, что я должен знать об этом? Любые хорошие ссылки на дополнительную информацию об этом?

Например:

25.times { | i | puts i }

Ответы [ 3 ]

27 голосов
/ 22 ноября 2010

Скобки определяют анонимную функцию, называемую блоком. Токены между каналом являются аргументами этого блока. Количество требуемых аргументов зависит от того, как используется блок. Каждый раз, когда блок оценивается, метод, требующий этого блока, будет передавать значение на основе вызывающего его объекта.

Это то же самое, что и определение метода, только оно не сохраняется за пределами метода, который принимает блок.

Например:

def my_print(i) 
  puts i
end

будет выполнять то же самое при выполнении:

{|i| puts i}

единственное отличие состоит в том, что блок определяется на лету и не сохраняется.

Пример 2: Следующие утверждения эквивалентны

25.times &method(:my_print)

25.times {|i| puts i}

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

Так что же происходит, когда метод принимает блок? Это зависит от метода. Методы, которые принимают блок, будут вызывать его, передавая значения из вызывающего объекта четко определенным образом. То, что возвращается, зависит от метода, требующего блока.

Например: In 25.times {|i| puts i} .times вызывает блок один раз для каждого значения от 0 до значения его вызывающего, передавая значение в блок как временную переменную i. Times возвращает значение вызывающего объекта. В этом случае 25.

Давайте рассмотрим метод, который принимает блок с двумя аргументами.

{:key1 => "value1", :key2 => "value2"}.each {|key,value| 
     puts "This key is: #{key}. Its value is #{value}"
}

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

5 голосов
/ 22 ноября 2010

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

Например, each_with_index использует две переменные и помещает элемент в одну из них, а индекс - в другую.

хорошее описание работы блоков и итераторов

2 голосов
/ 22 ноября 2010

Аргументы блока следуют тем же соглашениям, что и параметры метода (по крайней мере, начиная с 1.9): вы можете определить необязательные аргументы, списки аргументов переменной длины, значения по умолчанию и т. Д. *

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

i = 10
25.times { | i | puts i }
puts i #=> prints '10'

Напечатает '10' в конце. Поскольку иногда это является желательным поведением, даже если вы не передаете значение (т.е. вы хотите убедиться, что случайно не забили переменную из окружающей области видимости), вы можете указывать имена локальных переменных блока после точки с запятой после списка аргументов:

x = 'foo'
25.times { | i ; x | puts i; x = 'bar' }
puts x #=> prints 'foo'

Здесь 'x' является локальным для блока, даже если значение не передается.

...