Lorsque des blocs sont plus utiles que les fonctions (Ruby)?
-
16-12-2019 - |
Question
J'ai deux exemples qui donnent le même résultat.
avec bloc:
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
et avec la méthode:
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 deuxième solution semble plus simple, mais j'ai trouvé des usages de la première dans notre code d'application.Ma question est la suivante: dans quelle situation le premier est recommandé?Quels sont les avantages et les inconvénients de chacun?
La solution
La principale différence entre un bloc et une fonction selon votre exemple est que le bloc fonctionne dans le contexte de la fonction d'appel .
Donc, si votre exemple était comme:
def self.do_something(object_id)
x = "boogy on"
self.with_params(object_id) do |params|
some_stuff(params)
puts x
end
end
Le code dans le bloc peut accéder à la variable X qui a été défini à l'extérieur du bloc. Ceci s'appelle une fermeture. Vous ne pouviez pas faire cela si vous appeliez simplement une fonction selon votre deuxième exemple.
Une autre chose intéressante sur les blocs est qu'elles peuvent affecter le flux de contrôle de la fonction extérieure. Il est donc possible de faire:
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 l'appel quelque_stuff dans le bloc renvoie une valeur réelle, le bloc reviendra. Cela reviendra hors du bloc et hors de la méthode dossée . Porkleworkle n'obtiendrait pas la sortie.
Dans vos exemples, vous ne vous appuyez pas de l'une ou l'autre d'entre eux, il est donc probable que les appels de fonction sont probablement beaucoup plus propres.
Cependant, de nombreuses situations sont de nombreuses situations où utiliser des blocs pour vous permettre de profiter de ces choses sont inestimables.
Autres conseils
Normalement, les gens utilisent des blocs lorsqu'ils veulent exécuter un morceau de code à l'intérieur d'un autre morceau de code.Exemples:
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
Ces blocs sont fermés sur leur contexte lexical (ils capturent des variables de l'endroit où le bloc est déclaré et les transporter à la place lorsque des blocs sont appelés).
Structure schématique d'une méthode qui accepte un bloc.
def transaction
open_transaction # pre- part
yield if block_given? # run provided code
commit_transaction # post- part
rescue
rollback_transaction # handle problems
end
Dans votre premier exemple, l'utilisation d'un bloc est probablement injustifiée (IMHO).Trop complexe sans raison apparente.
Lorsque vous appelez avec_params (), vous envoyez non seulement des données, vous fournissez également du code à exécuter.Voir si différents blocs sont envoyés dans l'appel avec_Params ():
...
self.with_params(object_id) do |params|
some_other_stuff()
some_stuff(params)
end
...
et ailleurs:
...
self.with_params(object_id) do |params|
even_more_stuff(params)
end
...
Si les blocs sont tous identiques ou avec_params () est simplement appelé à partir d'un endroit, vous pourriez envisager d'éliminer les blocs.
Pour résumer: Utilisez des blocs si vous souhaitez passer à la méthode Différents bits de code (blocs) ainsi que des données: Hey with_params, prenez ces données (Object_id) et, à la manière, exécutez ce code (bloc)Pendant que vous êtes à cela.
BTW Vous faites différentes choses dans les deux exemples: avec_params () renvoie
some_stuff(params_hash)
Après avoir évalué le bloc.Et get_params () vient de retourner
params_hash
Un bloc comptez totalement sur votre code, mais une fonction a son propre code.
Donc, si votre code varie en situation de situation, utilisez le bloc. Sinon, construisez une fonction et utilisez-la comme boîte à blocs.