使用do block vs braces {}

新的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 cookbook说括号语法的优先顺序高于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作为参数传递给method1! 这相当于method1(method2){ puts "hi" }

但如果你说

 method1 method2{ puts "hi" } 

然后将使用块调用method2,然后将返回的值作为参数传递给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 } 

#### output ####

 #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 like:

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

基本上,它归结为,如果您的块逻辑转到多行并且不能安装在同一行上,那么使用do .. end ,如果您的块逻辑很简单,只需要简单/单行代码,那么使用{}

在Ruby中选择do end{ }有两种常见的样式:

Ruby on Rails推广了第一种非常常见的风格,它基于单行与多行的简单规则:

  • 使用大括号{ }表示单行块
  • 对多行块使用do end

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

第二种,不常见的风格被称为语义,或称为“ Weirich Braces ”,由已故的伟大的ruby师Jim Weirich提出:

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

这意味着当对块的返回值进行求值时 ,它应该是可链接的,并且{}大括号对方法链更有意义。

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

语法中的这种区别传达了关于块的评估的视觉含义,以及您是否应该关心其返回值。

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

 items.map { |i| i.upcase } 

但是,这里没有使用块的返回值。 它在程序上运行,并与它产生副作用:

 items.each do |item| puts item end 

语义样式的另一个好处是,您不需要更改大括号来执行/结束只是因为已将一行添加到块中。

作为观察,巧合的function块通常是单行的,并且程序块(例如,配置)是多行的。 因此,遵循Weirich风格最终看起来与Rails风格几乎相同。