2011-11-17 13 views
50

Estoy tratando de definir un bloque que usaré para pasar cada método de rangos múltiples. En lugar de redefinir el bloque en cada gama, me gustaría crear un lamba, y pasar el lambda como tal:Pasando una lambda como un bloque

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

Sin embargo, me sale el siguiente error:

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

Alguna idea de lo que está pasando aquí?

Respuesta

65

Tack un símbolo de unión (&) sobre el argumento, por ejemplo:

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

Esto significa que estás pasando como el parámetro de bloque especial del método. De lo contrario, se interpreta como un argumento normal.

También refleja que la forma que habían capturar y acceder el parámetro de bloque dentro del propio método:

# 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

El truco está en utilizar un & que le dice a Rubí para convertir este argumento a un Proc si es necesario y luego usa el objeto como el bloque del método. A partir de Ruby 1.9 hay un atajo para funciones lambda (anónimas). Por lo tanto, puede escribir código como este:

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

se llevará a cada elemento de la matriz y calcular su poder

es el mismo que el código:

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

para Ruby 1.8:

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

Para resolver su problema, puede utilizar el método de reduce array (0 es el valor inicial):

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

Pasar una función lambda a reduce es un poco complicado, pero el bloque anónimo es más o menos lo mismo que lambda.

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

O usted podría concat cartas como ésta:

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

Convertir a minúsculas:

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

En el contexto de la definición de un método, poniendo un signo delante de la última parámetro indica que un método puede tomar un bloque y nos da un nombre para referirse a este bloque dentro del cuerpo del método.

Cuestiones relacionadas