Ruby多行块函数不使用do end

24

我是一个Ruby的初学者,很抱歉要问这么简单的问题,但是这段代码有什么问题吗 -

3.upto(9) {
  print "Hello"
  puts " World"
}
或者
3.upto(9) { |n|
  print "Hello "
  puts n
}
它运行得足够好,但我看到的大多数代码示例都使用

的语法。
3.upto(9) do |n|
  print "Hello "
  puts n
end

只使用花括号来表示单个语句是一个惯例吗?对我来说,从C/C#转过来,第一种方式似乎更自然,但入乡随俗!


3个回答

51

两种语法之间有微妙的差别。{ }的优先级高于do ... end。 因此,以下代码将传递bar和一个块给方法foo

foo bar do ... end

下面的代码将向 bar 传递一个块,并将其结果传递给 foo:

foo bar { ... }

所以你的例子将会表现相同。不过,如果你省略了括号:

> 3.upto 9 { 
  puts "Hi" 
}
SyntaxError: compile error
(irb):82: syntax error, unexpected '{', expecting $end
3.upto 9 { 
          ^
    from (irb):82
    from :0

> 3.upto 9 do 
    puts "Hi" 
  end
Hi
Hi
Hi
Hi
Hi
Hi
Hi
=> 3

因此,在Ruby中如果你忘记使用括号,{ } 更容易出现错误,这是相当常见的;出于这个原因,并且因为Ruby的条件语句和其他控制结构都使用end作为定界符,人们通常在语句末尾使用 do ... end 来表示多行代码块。

然而,{ } 经常用于使用 do ... end 会很麻烦的地方,例如,如果您需要将几个需要带有块的方法链接在一起。 这可以让您编写短小的一行代码块,这些块可以作为方法链的一部分使用。

> [1,2,3].sort{|x,y| y<=>x}.map{|x| x+1}
=> [4, 3, 2]

这里有个例子可以说明它们之间的区别:

def foo arg
  if block_given?
    puts "Block given to foo"
    yield arg
  else
    puts "No block given to foo"
    arg
  end
end


def bar
  if block_given?
    puts "Block given to bar"
    yield "Yielded from bar"
  else
    puts "No block given to bar"
  end
  "Returned from bar"
end

irb(main):077:0> foo bar { |arg| puts arg }
Block given to bar
Yielded from bar
No block given to foo
=> "Returned from bar"
irb(main):078:0> foo bar do |arg| puts arg end
No block given to bar
Block given to foo
Returned from bar
=> nil

然而,{} 可以在 do 无法使用的情况下使用,例如,如果您正在链接多个需要块的方法。这不是真的。do 在链接中可以很好地使用。 [1,2,3].map do |x| x+1 end.each do |x| puts x end 可以正常工作。 - sepp2k
@sepp2k 你说得对,关于那个情况我错了。我已经更新了我的答案,表明那种情况只是一种风格问题。 - Brian Campbell
2年半后,这个回答非常好,非常有帮助。 - WestCoastProjects
13年过去了,仍然很棒!谢谢! - JakeRobb

6
这只是惯例而已。

1
特别是,在多行情况下,惯例是使用 do 语法,而在单行情况下则使用花括号...但请参考关于优先级的答案以获得更详细的解答。 - Jed Schneider

0

这里有seamless。来自README:

Python允许您使用缩进来表示代码块的结束。Ruby则遭受了极度冗长和繁琐的块终止符"end"。就像Lisp最终会有数十个闭合括号一样,频繁使用模块和类的Ruby文件最终会有大量不必要的"ends"。

编写一个Ruby文件,但跳过所有的"ends"。像在Python中一样排列您的代码块。然后只需将其命名为'your_file.rbe',require 'seamless'和require 'your_file'。Seamless会做剩下的事情。

这是否会被广泛使用?我不知道。但这非常有趣!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接