Передача лямбды в виде блока
Я пытаюсь определить блок, который я буду использовать для передачи каждого метода нескольких диапазонов. Вместо того, чтобы переопределять блок на каждом диапазоне, я хотел бы создать ламбу и передать лямбду как таковую:
count = 0
procedure = lambda {|v| map[count+=1]=v}
("A".."K").each procedure
("M".."N").each procedure
("P".."Z").each procedure
однако, я получаю следующую ошибку:
ArgumentError: wrong number of arguments(1 for 0) from code.rb:23:in `each'
есть идеи, что здесь происходит?
2 ответа:
Тэкс амперсанд (
&
) на аргумент, например:("A".."K").each &procedure
это означает, что вы передаете его как специальный параметр блока метода. В противном случае это интерпретируется как обычный аргумент.
Он также отражает их способ захвата и доступа к параметру блока внутри самого метода:
# the & here signifies that the special block parameter should be captured # into the variable `procedure` def some_func(foo, bar, &procedure) procedure.call(foo, bar) end some_func(2, 3) {|a, b| a * b } => 6
трюк заключается в использовании
&
что говорит Ruby преобразовать этот аргумент вProc
при необходимости, а затем использовать объект в качестве метода блока. Начиная с Ruby 1.9 есть ярлык для лямбда (анонимных) функций. Итак, вы можете написать такой код:(1..5).map &->(x){ x*x } # => [1, 4, 9, 16, 25]
возьмет каждый элемент массива и вычислит его мощность
это то же самое, что и этот код:
func = ->(x) { x*x } (1..5).map &func
для Ruby 1.8:
(1..5).map &lambda {|x| x*x} # => [1, 4, 9, 16, 25]
чтобы решить вашу проблема вы можете использовать метод массива
reduce
(0
- исходное значение):('A'..'K').reduce(0) { |sum,elem| sum + elem.size } # => 11
передача лямбда-функции в
reduce
немного сложно, но анонимный блок такой же, как и лямбда.('A'..'K').reduce(0) { |sum, elem| ->(sum){ sum + 1}.call(sum) } # => 11
или вы могли бы сцепить буквы так же, как это:
('A'..'K').reduce(:+) => "ABCDEFGHIJK"
преобразование в нижний регистр:
('A'..'K').map &->(a){ a.downcase } => ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
в контексте определения метода установка амперсанда перед последним параметром указывает на то, что метод может принимать блок и дает нам имя для ссылки на этот блок в теле метода.