2012-03-15 18 views
6

Tengo dos ejemplos que dan el mismo resultado.Cuando los bloques son más útiles que las funciones (ruby)?

Con bloque:

def self.do_something(object_id) 
    self.with_params(object_id) do |params| 
    some_stuff(params) 
    end 
end 

def self.with_params(object_id, &block) 
    find_object_by_id 
    calculate_params_hash 
    block.call(params_hash) 
end 

y con el método:

def self.do_something(object_id) 
    some_stuff(self.get_params(object_id)) 
end 

def self.get_params(object_id) 
    find_object_by_id 
    calculate_params_hash 
    params_hash 
end 

La segunda solución parece más sencillo, pero he encontrado algunos usos de la primera de ellas en nuestro código de la aplicación. Mi pregunta es: ¿en qué situación se recomienda la primera? ¿Cuáles son los pros y los contras de cada uno?

+0

En su ejemplo, no creo que haya una razón para usar el objeto Proc. El objetivo de los objetos de Proc es hacerlos persistir en el entorno léxico y pasarlos a otras funciones como argumentos. –

+0

agregó "proc" como etiqueta. –

+0

¿Qué significa 'some_stuff (params)', devuelve algo? – nkm

Respuesta

2

La principal diferencia entre un bloque y la función como por su ejemplo de ello es que el bloque se ejecuta en el contexto de la función de llamada.

Así que si su ejemplo fue como:

def self.do_something(object_id) 
    x = "boogy on" 
    self.with_params(object_id) do |params| 
    some_stuff(params) 
    puts x 
    end 
end 

El código del bloque puede acceder a la variable x que se definió fuera del bloque. Esto se llama cierre. No podría hacer esto si estuviera llamando a una función según su segundo ejemplo.

Otra cosa interesante acerca de los bloques es que pueden afectar el flujo de control de la función externa.Por lo que es posible hacer:

def self.do_something(object_id) 
    self.with_params(object_id) do |params| 
    if some_stuff(params) 
     return 
    end 
    end 

    # This wont get printed if some_stuff returns true. 
    puts "porkleworkle" 
end 

Si la llamada some_stuff dentro del bloque devuelve un valor verdadero, el bloque volverá. Esto saldrá del bloque y del método de dosificación. porkleworkle no obtendría salida.

En sus ejemplos, no confíe en ninguno de estos, por lo que usar llamadas de función es probablemente mucho más limpio.

Sin embargo, hay muchas situaciones en las que el uso de bloques para permitirle aprovechar estas cosas es invaluable.

3

Normalmente, las personas usan bloques cuando quieren ejecutar un código dentro de otro código. Ejemplos:

DB.with_shard_for_user(user_id) do |db| 
    # perform operations on a user's shard 

end # shard is reverted back to original value 

File.new(filename) do |file| 
    # work with file 
end # file is closed automatically 

User.transaction do 
    # run some operations as a single transaction 
end 

Estos bloques están cerrados en su contexto léxico (que capturan las variables de donde se declara el bloque, y los llevan hacia el lugar cuando los bloques se llaman).

Estructura esquemática de un método que acepta un bloque.

def transaction 
    open_transaction # pre- part 

    yield if block_given? # run provided code 

    commit_transaction # post- part 
rescue 
    rollback_transaction # handle problems 
end 

En su primer ejemplo, el uso de un bloque probablemente no esté justificado (en mi humilde opinión). Demasiado complejo sin razón aparente.

1

Cuando llama con_params(), no solo está enviando datos, sino que también proporciona algún código para ejecutar. A ver si los diferentes bloques son enviados a los with_params() llame a:

... 
self.with_params(object_id) do |params| 
    some_other_stuff() 
    some_stuff(params) 
end 
... 

y en otro lugar:

... 
self.with_params(object_id) do |params| 
    even_more_stuff(params) 
end 
... 

Si los bloques son todos iguales o with_params() llama simplemente de un lugar a continuación, podría considerar eliminar los bloques.

En resumen: utilice bloques si desea pasar al método diferentes bits de código (bloques) así como datos: hey con_parámetros, tome estos datos (object_id) y, dicho sea de paso, ejecute este código (bloque) mientras estás en eso.

Por cierto que están haciendo cosas diferentes en los dos ejemplos: with_params() devuelve

some_stuff(params_hash) 

después de evaluar el bloque. Y get_params() simplemente devuelve

params_hash 
1

Un bloque depende totalmente de su código, pero una función tiene su propio código.

Por lo tanto, si su código varía situación por situación, use bloque. De lo contrario, cree una función y úselo como cuadro de bloque.

Cuestiones relacionadas