2011-11-17 21 views
50

Próbuję zdefiniować blok, którego użyję do przekazania każdej metody z wielu zakresów. Zamiast przedefiniowanie bloku na każdym zakresie, chciałbym stworzyć Lamba i przekazać lambda jako takie:Przekazywanie lambda jako bloku

count = 0 
procedure = lambda {|v| map[count+=1]=v} 
("A".."K").each procedure 
("M".."N").each procedure 
("P".."Z").each procedure 

Jednak pojawia się następujący błąd:

 
ArgumentError: wrong number of arguments(1 for 0) 
    from code.rb:23:in `each' 

pomysłów, co się dzieje się tutaj?

Odpowiedz

65

Tack ampersand (&) na argumencie, na przykład:

("A".."K").each &procedure 

Oznacza to, że jesteś przechodzącą go jako specjalnego parametru bloku metody. W przeciwnym razie jest interpretowany jako zwykły argument.

odzwierciedla również ich sposób chcesz uchwycić i otworzyć parametr bloku wewnątrz samej metody:

# 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 
12

Sztuką jest w przy użyciu & który mówi Ruby przekonwertować ten argument do Proc jeśli to konieczne i następnie użyj obiektu jako bloku metody. Począwszy od wersji 1.9, istnieje skrót do funkcji lambda (anonimowych). Tak, można napisać kod tak:

(1..5).map &->(x){ x*x } 
# => [1, 4, 9, 16, 25] 

weźmie każdy element tablicy i obliczyć jego moc

to jest taki sam jak ten kod:

func = ->(x) { x*x } 
(1..5).map &func 

Ruby 1.8:

(1..5).map &lambda {|x| x*x} 
# => [1, 4, 9, 16, 25] 

w celu rozwiązania tego problemu można użyć metody Array reduce (0 jest wartość początkowa):

('A'..'K').reduce(0) { |sum,elem| sum + elem.size } 
# => 11 

Podjęcie funkcji lambda do reduce jest nieco skomplikowane, ale anonimowy blok jest prawie taka sama jak lambda.

('A'..'K').reduce(0) { |sum, elem| ->(sum){ sum + 1}.call(sum) } 
# => 11 

Albo można Concat litery podobnie jak ten:

('A'..'K').reduce(:+) 
=> "ABCDEFGHIJK" 

Konwersja na małe litery:

('A'..'K').map &->(a){ a.downcase } 
=> ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"] 

W kontekście definicji metody, kładąc ampersanda przed ostatnią parametr wskazuje, że metoda może przyjąć blok i podaje nam nazwę, która odnosi się do tego bloku w treści metody.

Powiązane problemy