Ruby中的块和产量

我试图理解块和yield ,以及它们如何在Ruby中工作。

如何使用yield ? 我看过的许多Rails应用程序都以一种奇怪的方式使用yield

有人可以向我解释或告诉我去哪里了解他们吗?


是的,起初有点令人费解。

在Ruby中,方法可以接收代码块以执行任意代码段。

当一个方法需要一个块时,它通过调用yield函数来调用它。

例如,这非常方便,可以遍历列表或提供自定义算法。

以下面的例子:

我将定义一个用名称初始化的Person类,并提供一个do_with_name方法,该方法在被调用时只传递name属性到所接收的块。

class Person 
    def initialize( name ) 
         @name = name
    end

    def do_with_name 
        yield( @name ) 
    end
end

这将允许我们调用该方法并传递任意代码块。

例如,要打印我们要做的名字:

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的值填充此参数。

yield( @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 ) - 它只是一个不同的块。

这个例子很简单。 更有趣的用法是过滤数组中的所有元素:

 days = ["monday", "tuesday", "wednesday", "thursday", "friday"]  

 # select those which start with 't' 
 days.select do | item |
     item.match /^t/
 end

=> ["tuesday", "thursday"]

或者,我们还可以提供自定义排序算法,例如基于字符串大小:

 days.sort do |x,y|
    x.size <=> y.size
 end

=> ["monday", "friday", "tuesday", "thursday", "wednesday"]

我希望这可以帮助你更好地理解它。

顺便说一句,如果该块是可选的,你应该这样称呼它:

yield(value) if block_given?

如果不是可选的,只需调用它。


在Ruby中,方法可以检查它们是否被调用,除了正常参数之外还提供了一个块。 通常这是使用block_given?完成的block_given? 方法,但您也可以通过在最终参数名称前加一个&符号( & )来将该块称为明确的Proc。

如果一个方法被一个块调用,那么如果需要的话,该方法可以用一些参数yield对块的调用(调用块)。 考虑这个示例方法,它演示了:

def foo(x)
  puts "OK: called as foo(#{x.inspect})"
  yield("A gift from foo!") if block_given?
end

foo(10)
# OK: called as foo(10)
foo(123) {|y| puts "BLOCK: #{y} How nice =)"}
# OK: called as foo(123)
# BLOCK: A gift from foo! How nice =)

或者,使用特殊块参数语法:

def bar(x, &block)
  puts "OK: called as bar(#{x.inspect})"
  block.call("A gift from bar!") if block
end

bar(10)
# OK: called as bar(10)
bar(123) {|y| puts "BLOCK: #{y} How nice =)"}
# OK: called as bar(123)
# BLOCK: A gift from bar! How nice =)

很有可能有人会在这里提供一个真正详细的答案,但是我总是发现Robert Sosinski的这篇文章是对块,procs和lambda之间细微差别的一个很好的解释。

我应该补充一点,我相信我链接的帖子是针对Ruby 1.8的。 有些事情在ruby 1.9中已经改变了,比如block变量是块本地的。 在1.8中,你会得到如下内容:

>> a = "Hello"
=> "Hello"
>> 1.times { |a| a = "Goodbye" }
=> 1
>> a
=> "Goodbye"

而1.9会给你:

>> a = "Hello"
=> "Hello"
>> 1.times { |a| a = "Goodbye" }
=> 1
>> a
=> "Hello"

我在这台机器上没有1.9,所以上面可能有错误。

链接地址: http://www.djcxy.com/p/4387.html

上一篇: Blocks and yields in Ruby

下一篇: Understanding the Rails Authenticity Token