小编典典

Ruby 中的块和产量

all

我正在尝试了解块以及yield它们在 Ruby 中的工作方式。

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

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


阅读 102

收藏
2022-04-20

共1个答案

小编典典

是的,一开始有点令人费解。

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

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

例子:

Person,一个具有name属性和do_with_name方法的类。当方法被调用时,它会将name属性传递给块。

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

    def do_with_name   # expects a block
        yield( @name ) # invoke the block and pass the `@name` attribute
    end
end

现在您可以调用此方法并传递任意代码块。

person = Person.new("Oscar")

# Invoking the method passing a block to print the value
person.do_with_name do |value|
    puts "Got: #{value}"
end

将打印:

Got: Oscar

请注意,该块接收一个名为 的变量作为参数value。当代码调用yield它作为参数传递的值@name

yield( @name )

可以使用不同的块调用相同的方法。

例如反转名称:

reversed_name = ""

# Invoke the method passing a different block
person.do_with_name do |value| 
    reversed_name = value.reverse
end

puts reversed_name

=> "racsO"

其他更有趣的现实生活示例:

过滤数组中的元素:

 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?

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

irb您可以使用(交互式 Ruby
Shell
)在您的计算机上尝试这些示例

以下是复制/粘贴就绪形式的所有示例:

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

    def do_with_name   # expects a block
        yield( @name ) # invoke the block and pass the `@name` attribute
    end
end


person = Person.new("Oscar")

# Invoking the method passing a block to print the value
person.do_with_name do |value|
    puts "Got: #{value}"
end


reversed_name = ""

# Invoke the method passing a different block
person.do_with_name do |value| 
    reversed_name = value.reverse
end

puts reversed_name



# Filter elements in an array:    
days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]

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



# Sort by name length:     
days.sort do |x,y|
   x.size <=> y.size
end
2022-04-20