什么时候块比函数(红宝石)更有用?
Posted
技术标签:
【中文标题】什么时候块比函数(红宝石)更有用?【英文标题】:When blocks are more useful than functions (ruby)? 【发布时间】:2012-03-31 21:06:33 【问题描述】:我有两个给出相同结果的示例。
有块:
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
和方法:
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
第二种解决方案似乎更直接,但我在我们的应用程序代码中发现了第一种解决方案的一些用法。我的问题是:在哪种情况下推荐第一个?各有什么优缺点?
【问题讨论】:
在您的示例中,我认为没有理由使用 Proc 对象。 Proc 对象的全部意义在于使它们在词法环境中持续存在,并将它们作为参数传递给其他函数。some_stuff(params)
有什么作用,它会返回什么吗?
它是“方法”,而不是 ruby 中的“功能”。
【参考方案1】:
当人们想要在另一段代码中运行一段代码时,通常会使用块。例子:
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
这些块在它们的词法上下文上是封闭的(它们从声明块的地方捕获变量,并将它们带到调用块的地方)。
接受块的方法的示意图结构。
def transaction
open_transaction # pre- part
yield if block_given? # run provided code
commit_transaction # post- part
rescue
rollback_transaction # handle problems
end
在您的第一个示例中,使用块可能是不合理的(恕我直言)。太复杂了,没有明显的原因。
【讨论】:
【参考方案2】:根据您的示例,块和函数之间的主要区别在于块在调用函数的上下文中运行。
如果你的例子是:
def self.do_something(object_id)
x = "boogy on"
self.with_params(object_id) do |params|
some_stuff(params)
puts x
end
end
块内的代码可以访问在块外定义的变量 x。这称为闭包。如果您只是按照第二个示例调用函数,则无法执行此操作。
关于块的另一个有趣的事情是它们可以影响外部函数的控制流。所以可以这样做:
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
如果块内的 some_stuff 调用返回真值,则块将返回。这将退出块并退出 dosomething 方法。 porkleworkle 不会得到输出。
在您的示例中,您不依赖其中任何一个,因此使用函数调用可能更简洁。
但是,在许多情况下,使用块来让您利用这些东西是非常宝贵的。
【讨论】:
【参考方案3】:当您调用 with_params() 时,您不仅发送了数据,还提供了一些运行代码。查看是否将不同的块发送到 with_params() 调用中:
...
self.with_params(object_id) do |params|
some_other_stuff()
some_stuff(params)
end
...
还有其他地方:
...
self.with_params(object_id) do |params|
even_more_stuff(params)
end
...
如果块都相同或只是从一个地方调用 with_params(),那么您可以考虑消除这些块。
总结一下:如果你想将不同位的代码(块)和数据传递给方法,请使用块:嘿,with_params,取这个数据(object_id),顺便说一下,运行这个代码(块)当你在它的时候。
顺便说一句,你在这两个例子中做了不同的事情:with_params() 返回
some_stuff(params_hash)
在评估块之后。而 get_params() 只是返回
params_hash
【讨论】:
【参考方案4】:一个块完全依赖你的代码,但一个函数有它自己的代码。
因此,如果您的代码因情况而异,请使用块。 如果没有,请构建一个函数并将其用作块框。
【讨论】:
以上是关于什么时候块比函数(红宝石)更有用?的主要内容,如果未能解决你的问题,请参考以下文章
[react] 在React中什么时候使用箭头函数更方便呢?
2020.07.11 创建的新角色拥有创建的有用的物品(①各个职业的装备包;②36格的包裹*5;③传送宝石)