使用 do 块 vs 大括号{}

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

Is there any difference (obscure or practical) between the following two snippets?

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


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

I realize the brace syntax would allow you to place the block on one line

my_array.each { |item| puts item }

但除此之外,还有什么令人信服的理由使用一种语法而不是另一种语法吗?

60954 次浏览

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 }

一般来说,惯例是在执行小型操作时使用 {},例如,方法调用或比较等,因此这非常有意义:

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,如果你的块逻辑是简单的,只是一个简单的/单行代码,然后使用 {}

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

就像以前说的那样

括号语法的优先级高于 do. . end

but how this one makes difference:

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
}

输出

#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

对于 Ruby 中的块,选择 do end{ }有两种常见的风格:

第一个也是最常见的样式是由 Ruby on Rails 推广的,它基于单行与多行的简单规则:

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

这是有意义的,因为 do/end 在一行程序中读取很差,但是对于多行块来说,将结束的 }挂在自己的行上与在 Ruby 中使用 end的其他所有内容不一致,例如模块、类和方法定义(def等)和控制结构(ifwhilecase等)

第二种不太常见的红宝石风格被称为语义风格,或“ 韦里奇 · 布雷斯”,由已故的伟大红宝石学家吉姆•韦里奇(Jim Weirich)提出:

  • 对过程块使用 do end
  • Use braces { } for functional blocks

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

另一方面,当对代码块的 副作用进行求值时,返回值是无关紧要的,代码块只是在“做”某些事情,因此被链接是没有意义的。

语法中的这种区别传达了关于块的计算以及是否应该关心它的返回值的可视化意义。

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

items.map { |i| i.upcase }

然而,这里它没有使用代码块的返回值,而是按照程序操作,做什么是它的一个副作用:

items.each do |item|
puts item
end

语义样式的另一个好处是,不需要仅仅因为在块中添加了一行就更改大括号来执行/结束操作。

作为一个观察,巧合的是,功能性的块通常是一行代码,而 程序上的块(例如 config)是多行代码。因此,遵循 Weirich 风格最终看起来几乎与 Rails 风格相同。

我使用韦里奇风格多年,但刚刚从这个转移到 一定要戴牙套。我不记得曾经使用过的信息从块风格,和定义是有点模糊。例如:

date = Timecop.freeze(1.year.ago) { format_date(Time.now) }
customer = Timecop.freeze(1.year.ago) { create(:customer) }

这些是程序性的还是功能性的?

在我看来,线数这东西毫无用处。我知道,是否有一个或更多的行,为什么确切地说,我应该改变样式,只是因为我已经添加或删除行?