Ruby '的不同行为;做结束';及;{..};红宝石块

Ruby '的不同行为;做结束';及;{..};红宝石块,ruby,Ruby,对不起,如果这个问题是重复的。但是我找不到用法上的区别。当我运行下面的代码时,我得到了不同的答案。我从大多数教程中看到,“do…end”的使用与“{…}”块相同 包括可比较的 a=[1,4,2,3,5] p a.排序do | x,y| y x 结束 输出显示为=[1,2,3,4,5] 但是当我像这样跑的时候 include Comparable a = [1, 4, 2, 3, 5] p a.sort { |x,y| y <=> x } 包括可比较的 a=[1,4,2

对不起,如果这个问题是重复的。但是我找不到用法上的区别。当我运行下面的代码时,我得到了不同的答案。我从大多数教程中看到,“do…end”的使用与“{…}”块相同

包括可比较的
a=[1,4,2,3,5]
p a.排序do | x,y|
y x
结束
输出显示为=[1,2,3,4,5]

但是当我像这样跑的时候

include Comparable

a = [1, 4, 2, 3, 5]

p a.sort { |x,y|
    y <=> x
}
包括可比较的
a=[1,4,2,3,5]
p a.排序{| x,y|
y x
}
输出显示为=[5,4,3,2,1]


这里出了什么问题。两个语法有不同的行为吗?

优先级不同。第一种解释为

p (a.sort) do
  ...
end

由于块未传递给排序,因此它按默认的升序排序。然后,该块被传递给不使用它的
p

正如其他人所指出的,这两种类型的块之间的优先级不同。然而,优先级并不真正影响它在实践中的使用

一些红宝石学家遵循这一原则

简而言之,一种方法的使用取决于它是功能性的(使用返回值),在这种情况下使用
{…}
,还是过程性的(以某种方式更改系统状态或执行输出),在这种情况下
执行。。。end使用了

萨瓦的回答是正确的,但由于OP要求进一步澄清,我将提供我自己的答案

这四个方法调用的行为都相同,将块传递给
foo
方法:

foo { ... }
foo do ... end
foo() { ... }
foo() do ... end
编写两个方法和一个块时,如果参数周围没有括号,则不清楚该块使用哪种方法:

foo bar { ... }
foo bar do ... end
问题是:“我是将块传递给
bar
,然后将其返回值传递给
foo
?还是将
bar
作为参数调用
foo
,同时传递块?”

使用圆括号,可以使用以下任一块样式来明确这一点:

# Passing a block to `bar`, and then passing the result to `foo`
foo( bar { ... } )
foo( bar do ... end )

# Passing an argument and  block to `foo`
foo( bar ) { ... }
foo( bar ) do ... end
您遇到的
{…}
do…end
之间的区别在于,当您省略括号时,Ruby会选择将它们放在括号中。两个块符号具有不同的优先级,因此以不同的结果结束:

# Passing a block to `bar`, and then passing the result to `foo`
foo bar{ ... }
foo( bar do ... end )

# Passing an argument and  block to `foo`
foo bar do ... end
foo( bar ){ ... }
因此,特别是在你的情况下:

# This code…
p a.sort do |x,y|
    y <=> x
end

# …is the same as this code:
b = a.sort
p(b){ |x,y| y <=> x }

# Note that you are passing a block to the `p` method
# but it doesn't do anything with it. Thus, it is
# functionally equivalent to just:
p a.sort

请注意,上面代码中的第一个和最后一个示例的区别仅在于它们是使用块的
{…}
还是
do…end

那么,我们是否必须使用
{…}
?。如果是,在哪些情况下我们应该使用
do…end
{…}
?您可以使用其中一种。正如奥斯卡所写,惯例是对多行使用
do…end
,对单行使用
{…}
。但是,如果您将
{…}
与接受参数的方法一起使用,您可能需要将参数用括号括起来,以清楚说明这一点。现在我了解到,我们可以同时使用这两种方法,其中一种用于单行,另一种用于多行。正如大家所说,这两种方法都是正确的,但仍然无法理解,为什么在我使用
do…end
时,输出显示出不同。请帮我理解一下?任何详细的解释都是值得欣赏的?这是一种非常有争议的风格。我和@Phrogz在一起。单行使用大括号,多行使用
begin。。。为清晰起见,结束
。显然,每个风格指南和程序员都有权发表自己的意见。我只是觉得这种特殊的风格很古怪,不太受欢迎。这种传统的问题是,两者并不相互排斥。有时,一个方法可能会有副作用/输出,并且可能会使用它的返回值。按照惯例,如果使用返回值,不管副作用如何,它都是一个功能块。然而,我建议以某种方式分割一个同时具有副作用和返回值的块,以使意图更加清晰。我认为这就是这个惯例背后的原因:让写作更容易,目的明确。正如Avdi所说,“它添加了一个关于代码意图的视觉提示,否则就不会出现了。”根据我的代码解释的示例,而不是所有的“foo…”示例,我知道了何时使用“{…}”和“do…end”。谢谢你的详细解释。非常感谢你的时间。
# This code…
p a.sort do |x,y|
    y <=> x
end

# …is the same as this code:
b = a.sort
p(b){ |x,y| y <=> x }

# Note that you are passing a block to the `p` method
# but it doesn't do anything with it. Thus, it is
# functionally equivalent to just:
p a.sort
# This code…
p a.sort { |x,y|
    y <=> x
}

# …is functionally the same as this code:
b = a.sort{ |x,y| y <=> x }
p b
def foo(a=nil)
  yield :foo if block_given?
end

def bar
  yield :bar if block_given?
  :bar_result
end

foo bar { |m| puts "block sent to #{m}" }
#=> block sent to bar
#=> foo got :bar_result

foo( bar do |m| puts "block sent to #{m}" end )
#=> block sent to bar
#=> foo got :bar_result

foo( bar ){ |m| puts "block sent to #{m}" }
#=> foo got :bar_result
#=> block sent to foo

foo bar do |m| puts "block sent to #{m}" end
#=> foo got :bar_result
#=> block sent to foo