使用块vs括号{}

新的ruby,戴上你的新手套。

以下两个片段之间有什么区别(模糊或实际)?

my_array = [:uno, :dos, :tres] my_array.each { |item| puts item } my_array = [:uno, :dos, :tres] my_array.each do |item| puts item end 

我意识到括号语法将允许您将块放在一行

 my_array.each { |item| puts item } 

但除此之外,是否有任何令人信服的理由使用一种语法?

Ruby的食谱说支架语法比do..end具有更高的优先顺序

请记住,括号语法比do..end语法具有更高的优先级。 考虑以下两个代码片段:

 1.upto 3 do |x| puts x end 1.upto 3 { |x| puts x } # SyntaxError: compile error 

第二个例子只有在括号被使用时才起作用, 1.upto(3) { |x| puts x } 1.upto(3) { |x| puts x }

这是一个有点老的问题,但我想尝试解释一些关于{}do .. end

就像之前所说的那样

括号语法比do..end具有更高的优先顺序

但是这个如何改变:

 method1 method2 do puts "hi" end 

在这种情况下,将使用do..end块调用method1,并将method2作为parameter passing给method1! 相当于method1(method2){ puts "hi" }

但如果你说

 method1 method2{ puts "hi" } 

那么method2将被调用,然后返回的值将作为parameter passing给method1。 这相当于method1(method2 do puts "hi" end)

 def method1(var) puts "inside method1" puts "method1 arg = #{var}" if block_given? puts "Block passed to method1" yield "method1 block is running" else puts "No block passed to method1" end end def method2 puts"inside method2" if block_given? puts "Block passed to method2" return yield("method2 block is running") else puts "no block passed to method2" return "method2 returned without block" end end #### test #### method1 method2 do |x| puts x end method1 method2{ |x| puts x } 

####输出####

 #inside method2 #no block passed to method2 #inside method1 #method1 arg = method2 returned without block #Block passed to method1 #method1 block is running #inside method2 #Block passed to method2 #method2 block is running #inside method1 #method1 arg = #No block passed to method1 

一般来说,惯例是在你做一个小的操作时使用{} ,例如方法调用或比较等等,所以这是非常有意义的:

 some_collection.each { |element| puts element } 

但是,如果你有一些稍微复杂的逻辑去多行,那么使用do .. end就像:

 1.upto(10) do |x| add_some_num = x + rand(10) puts '*' * add_some_num end 

基本上,如果你的块逻辑去多行,不能安装在同一行,那么使用do .. end ,如果你的块逻辑是简单的,只是一个简单的/单行的代码,然后使用{}

Ruby中有两种常见的selectdo end{ }的方式:

第一个也是非常常见的风格是Ruby on Rails所普及的,它基于单线和多线的简单规则:

  • 使用大括号{ }作为单行块
  • 使用do end多行块

这是有道理的,因为do / end在一行中严重读取,但是对于多行块,在其自己的行上留下一个闭合的结尾与使用ruby end所有其他内容不一致,例如模块,类和方法定义( def等)和控制结构( ifwhilecase等)

第二种不太常见的风格被称为语义,或由已故的伟大的ruby吉姆·维里奇(Jim Weirich)提出的“ Weirich Braces ”:

  • 使用do end程序块
  • 使用大括号{ }作为功​​能块

这意味着当块被评估为返回值时 ,它应该是可链接的,并且{}括号对于方法链接更有意义。

另一方面,当块被评估为副作用时 ,返回值是无关紧要的,块只是“做”了某些东西,所以被链接是没有意义的。

语法上的这种区分传达了关于块的评估的视觉意义,以及是否应该关心它的返回值。

例如,这里块的返回值应用于每个项目:

 items.map { |i| i.upcase } 

但是,这里没有使用块的返回值。 它在程序上运行,并且对它一个副作用:

 items.each do |item| puts item end 

语义风格的另一个好处是你不需要改变大括号来做/结束,只是因为一个行被添加到块中。

作为一个观察,巧合的function块通常是单线的, 程序块(例如configuration)是多线的。 所以,遵循Weirich风格最终看起来几乎和Rails风格一样。