Ruby 中的 &block 是什么?它是如何通过这里的方法传递的?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/814739/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What's this &block in Ruby? And how does it get passed in a method here?
提问by Malik Daud Ahmad Khokhar
Saw this piece of code in a Ruby on Rails book. This first one is from a view and the second one is a helper module. I don't understand how that &blockand the attributes={}thing work. Can anyone guide me to a tutorial of some kind explaining this?
在 Ruby on Rails 书中看到了这段代码。第一个来自视图,第二个是辅助模块。我不明白那&block和attributes={}事情是如何运作的。任何人都可以指导我进行某种教程来解释这一点吗?
<% hidden_div_if(@cart.items.empty?, :id => "cart") do %>
<%= render(:partial => "cart", :object => @cart) %>
<% end %>
module StoreHelper
def hidden_div_if(condition, attributes = {}, &block)
if condition
attributes["style"] = "display: none"
end
content_tag("div", attributes, &block)
end
end
回答by rampion
Blocks are a fairly basic part of ruby. They're delimited by either do |arg0,arg1| ... endor { |arg0,arg1,arg2| ... }.
块是 ruby 的一个相当基本的部分。它们由do |arg0,arg1| ... end或分隔{ |arg0,arg1,arg2| ... }。
They allow you to specify a callback to pass to a method.
This callback can be invoked two ways - either by capturing
it by specifying a final argument prefixed with &, or by
using the yieldkeyword:
它们允许您指定要传递给方法的回调。可以通过两种方式调用此回调 - 通过指定以 为前缀的最终参数&或使用yield关键字来捕获它:
irb> def meth_captures(arg, &block)
block.call( arg, 0 ) + block.call( arg.reverse , 1 )
end
#=> nil
irb> meth_captures('pony') do |word, num|
puts "in callback! word = #{word.inspect}, num = #{num.inspect}"
word + num.to_s
end
in callback! word = "pony" num = 0
in callback! word = "ynop" num = 1
#=> "pony0ynop1"
irb> def meth_yields(arg)
yield(arg, 0) + yield(arg.upcase, 1)
end
#=> nil
irb> meth_yields('frog') do |word, num|
puts "in callback! word = #{word.inspect}, num = #{num.inspect}"
word + num.to_s
end
in callback! word = "frog", num = 0
in callback! word = "FROG", num = 1
#=> "frog0FROG1"
Note that our callback was the same in each case - we can remove
repetition by saving our callback in an object, and then passing it to each
method. This can be done using lambdato capture the callback in an object,
and then passed to a method by prefixing it with &.
请注意,我们的回调在每种情况下都是相同的 - 我们可以通过将回调保存在一个对象中,然后将其传递给每个方法来消除重复。这可以通过lambda捕获对象中的回调来完成,然后通过在它前面加上前缀来传递给方法&。
irb> callback = lambda do |word, num|
puts "in callback! word = #{word.inspect}, num = #{num.inspect}"
word + num.to_s
end
#=> #<Proc:0x0052e3d8@(irb):22>
irb> meth_captures('unicorn', &callback)
in callback! word = "unicorn", num = 0
in callback! word = "nrocinu", num = 1
#=> "unicorn0nrocinu1"
irb> meth_yields('plate', &callback)
in callback! word = "plate", num = 0
in callback! word = "PLATE", num = 1
#=> "plate0PLATE1"
It's important to understand the different uses of &here as a prefix to the last argument of a function
了解&here 作为函数最后一个参数的前缀的不同用途很重要
- in a function definition, it captures any passed block into that object
- in a function call, it expands the given callback object into a block
- 在函数定义中,它将任何传递的块捕获到该对象中
- 在函数调用中,它将给定的回调对象扩展为一个块
If you look around blocks are used all over the place, especially in iterators, like Array#each.
如果你环顾四周,块到处都是,特别是在迭代器中,比如Array#each.
回答by gaqzi
The &blockis a way of sending a piece of Ruby code in to a method and then evaluating that code in the scope of that method. In your example code above it means a partial named cart will be rendered in a div. I think the term closureis used for this in computer science.
这&block是一种将一段 Ruby 代码发送到一个方法,然后在该方法的范围内评估该代码的方法。在上面的示例代码中,这意味着将在 div 中呈现部分命名的购物车。我认为术语闭包在计算机科学中用于此。
So in your example the &blockis:
所以在你的例子中&block是:
<%= render(:partial => "cart", :object => @cart) %>
Some good reading and an explanation of blocks, procs and lamdas can be found at Robert Sosinski's blog.
可以在Robert Sosinski 的博客中找到一些很好的阅读和对块、过程和 lamda 的解释。
回答by kch
Re attributes = {}, that's just a method argument with a default value. So if you call hidden_div_if(whatever), that is, passing only the first argument, attributeswould default to an empty hash.
Re attributes = {},这只是一个带有默认值的方法参数。因此,如果您调用hidden_div_if(whatever),即仅传递第一个参数,attributes将默认为空哈希。
That's useful because it simplifies setting attributes["style"]later, as attributesdoesn't have to be initialized to a hash first. (Which might nonetheless be done simply as (attributes ||= {})["style"] = ….)
这很有用,因为它简化了attributes["style"]以后的设置,因为attributes不必先初始化为散列。(尽管如此,这也可以简单地完成(attributes ||= {})["style"] = …。)
&blockis only slightly more complicated.
&block只是稍微复杂一些。
Ruby methods can take a last argument that is a block, using the special syntax method(args) { |block_args| block_code }. &blockbasically captures that block into the blockvariable as a Procobject. So blockis just a variable pointing to an anonymous procedure here.
Ruby 方法可以使用特殊语法 接受作为块的最后一个参数method(args) { |block_args| block_code }。&block基本上将该块block作为Proc对象捕获到变量中。所以block这里只是一个指向匿名过程的变量。
When later content_tagis called, and &blockis passed as its last argument, it's expanded into a block, like if the call was indeed content_tag(…) { block originally passed to hidden_if_div }
当 latercontent_tag被调用并&block作为最后一个参数传递时,它被扩展为一个块,就像调用确实是content_tag(…) { block originally passed to hidden_if_div }
So maybe I was really confusing here. What you should google for is "ruby default arguments" and "ruby blocks".
所以也许我在这里真的很困惑。你应该用谷歌搜索的是“ruby default arguments”和“ruby blocks”。
回答by jspooner
Ruby implements Blocks, Procs and lambdas which are referred to as closures in the computer science community. If you beginning to learn Ruby you will quickly run into code that looks like this.
Ruby 实现了 Blocks、Procs 和 lambdas,它们在计算机科学社区中被称为闭包。如果您开始学习 Ruby,您将很快遇到类似这样的代码。
a = ["dog", "cat", "bird"]
a.alter_each! do |n, i|
"#{i}_#{n}"
end
So whats going on here?
那么这里发生了什么?
We start off with an array of animal names and call the alter_each! method passing a block. In this block of code we can specify how we want to alter each item. Our example will prefix each animal name with it's position in the array. As the alter_each! method iterates through each item it will execute our block passing the value and index. Our block captures these params, prefixes the index to the name and returns the result. Now lets look at the alter_each! method.
我们从一系列动物名称开始,并调用 alter_each!传递块的方法。在这个代码块中,我们可以指定我们想要如何改变每个项目。我们的示例将使用它在数组中的位置作为每个动物名称的前缀。至于alter_each!方法遍历每个项目,它将执行我们传递值和索引的块。我们的块捕获这些参数,将索引作为名称的前缀并返回结果。现在让我们看看alter_each!方法。
Notice the method doesn't specify any params, that's because a block is automatically assigned to yield keyword. yield is called like a function passing in the value and index of each item in the array and overriding the original value.
请注意,该方法没有指定任何参数,这是因为块会自动分配给 yield 关键字。yield 的调用就像一个函数,传入数组中每个项目的值和索引并覆盖原始值。
class Array
def alter_each!
self.each_with_index do |n, i|
self[i] = yield(n,i)
end
end
end
What if you need to pass a param to this method?
如果你需要向这个方法传递一个参数怎么办?
You can modify the method signature to accept params and finally catch the block with a param starting with an ampersand. In the example below our block will be captured with the &block param which we will invoke the call method. This is in place of using yield
您可以修改方法签名以接受参数,并最终使用以与号开头的参数捕获块。在下面的示例中,我们的块将使用 &block 参数捕获,我们将调用 call 方法。这代替了使用产量
class Array
def modify_each!(add_one = true, &block)
self.each_with_index do |n, i|
j = (add_one) ? (i + 1) : i
self[i] = block.call(n,j)
end
end
end
回答by Miquel
It works like this:
它是这样工作的:
@cart.items.empty?is the codition
@cart.items.empty?是条件
:id => "cart"Becomes attributes as per convention you can remove {} on a param hash if it is last one.
:id => "cart"按照约定成为属性,如果它是最后一个,您可以删除参数哈希上的 {}。
the block is
块是
render(:partial => "cart", :object => @cart)
render(:partial => "cart", :object => @cart)
so within the function if the cart is empty it will add the attribute style with value "display: none"
所以在函数内,如果购物车为空,它将添加值为“display:none”的属性样式
Then it will create a div tag filled with the content of the result of executing the block which will be the result of rendering the partial view cart with the contents of @cart.
然后它会创建一个 div 标签,填充执行块的结果的内容,这将是使用@cart 的内容呈现局部视图购物车的结果。

