Ruby中的块和收益 [英] Blocks and yields in Ruby
问题描述
我试图了解块和yield
以及它们在Ruby中的工作方式.
I am trying to understand blocks and yield
and how they work in Ruby.
yield
如何使用?我看过的许多Rails应用程序都以怪异的方式使用yield
.
How is yield
used? Many of the Rails applications I've looked at use yield
in a weird way.
有人可以向我解释或告诉我去哪里了解他们?
Can someone explain to me or show me where to go to understand them?
推荐答案
是的,起初有点令人困惑.
Yes, it is a bit puzzling at first.
在Ruby中,方法可以接收代码块以执行任意代码段.
In Ruby, methods may receive a code block in order to perform arbitrary segments of code.
当方法需要一个块时,它通过调用yield
函数来调用它.
When a method expects a block, it invokes it by calling the yield
function.
例如,这非常方便,它可以遍历列表或提供自定义算法.
This is very handy, for instance, to iterate over a list or to provide a custom algorithm.
以下面的示例为例:
我将定义一个用名称初始化的Person
类,并提供一个do_with_name
方法,该方法在被调用时将把name
属性传递给接收到的块.
I'm going to define a Person
class initialized with a name, and provide a do_with_name
method that when invoked, would just pass the name
attribute, to the block received.
class Person
def initialize( name )
@name = name
end
def do_with_name
yield( @name )
end
end
这将允许我们调用该方法并传递任意代码块.
This would allow us to call that method and pass an arbitrary code block.
例如,要打印名称,我们将要做:
For instance, to print the name we would do:
person = Person.new("Oscar")
#invoking the method passing a block
person.do_with_name do |name|
puts "Hey, his name is #{name}"
end
会打印:
Hey, his name is Oscar
注意,该块接收一个名为name
的变量作为参数(注意,您可以随心所欲地将此变量命名为name
).当代码调用yield
时,它将用@name
的值填充此参数.
Notice, the block receives, as a parameter, a variable called name
(N.B. you can call this variable anything you like, but it makes sense to call it name
). When the code invokes yield
it fills this parameter with the value of @name
.
yield( @name )
我们可以提供另一个块来执行不同的操作.例如,将名称取反:
We could provide another block to perform a different action. For example, reverse the name:
#variable to hold the name reversed
reversed_name = ""
#invoke the method passing a different block
person.do_with_name do |name|
reversed_name = name.reverse
end
puts reversed_name
=> "racsO"
我们使用了完全相同的方法(do_with_name
)-它只是一个不同的块.
We used exactly the same method (do_with_name
) - it is just a different block.
这个例子很简单.更有趣的用法是过滤数组中的所有元素:
This example is trivial. More interesting usages are to filter all the elements in an array:
days = ["monday", "tuesday", "wednesday", "thursday", "friday"]
# select those which start with 't'
days.select do | item |
item.match /^t/
end
=> ["tuesday", "thursday"]
或者,我们也可以提供一种自定义排序算法,例如基于字符串大小的
Or, we can also provide a custom sort algorithm, for instance based on the string size:
days.sort do |x,y|
x.size <=> y.size
end
=> ["monday", "friday", "tuesday", "thursday", "wednesday"]
我希望这可以帮助您更好地理解它.
I hope this helps you to understand it better.
顺便说一句,如果该块是可选的,则应这样称呼它:
BTW, if the block is optional you should call it like:
yield(value) if block_given?
如果不是可选的,则只需调用它即可.
If is not optional, just invoke it.
编辑
@hmak为这些示例创建了一个repl.it: https://repl.it/@makstaks/blocksandyieldsrubyexample
@hmak created a repl.it for these examples: https://repl.it/@makstaks/blocksandyieldsrubyexample
这篇关于Ruby中的块和收益的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!