在Ruby中,if / elsif / else语句的从属块与“'块”相同。那是作为参数传递的?

时间:2017-08-02 00:29:16

标签: ruby terminology control-flow

我正在读一下Ruby中的if / elsif / else,在描述控制表达式如何工作时,我遇到了一些术语上的差异。

Ruby Programming Wikibooks中(强调添加):

  

条件分支获取测试表达式的结果并执行代码块,具体取决于测试表达式是true还是false。

  

例如,if表达式不仅可以确定从属代码块是否会执行,而且还会产生值本身。

然而,Ruby-doc.org在定义中根本没有提到块:

  

最简单的if表达式有两个部分,一个是“test”表达式,另一个是“then”表达式。如果“test”表达式的计算结果为true,则评估“then”表达式。

通常,当我读到关于'块'在Ruby中,它几乎总是在procs和lambdas的上下文中。例如,rubylearning.com定义了一个块:

  

Ruby 是一种对语句进行分组的方法,可能只出现在与方法调用相邻的源中; 从与方法调用的最后一个参数(或参数列表的右括号)相同的行开始写入。

问题:

  • 在谈论Ruby中的代码块时,我们是在讨论 传递给方法的代码组,或者我们是简单的 一般来说谈论一组代码?
  • 有没有办法轻松区分两者(并且存在 两者之间的技术差异)?

这些问题的上下文:我想知道是否引用条件内部的代码,因为 blocks 会在新的Ruby程序员被引入块,procs和lambdas时混淆。 / p>

1 个答案:

答案 0 :(得分:1)

TL; DR if...end是表达式,而不是块

在Ruby中正确使用术语block是传递给do...end或花括号{...}之间的方法的代码。通过使用方法签名中的Proc语法,可以并且通常将块隐式转换为方法中的&block。这个新的Proc是一个对象,它有自己的方法,可以传递给其他方法,存储在变量和数据结构中,重复调用等等......

def block_to_proc(&block)
  prc = block
  puts prc
  prc.class
end

block_to_proc { 'inside the block' }
# "#<Proc:0x007fa626845a98@(irb):21>"
# => Proc

在上面的代码中,隐式创建Proc,并将块作为其主体并分配给变量block。同样,Proc(或lambdaProc类型可以“扩展”为块,并通过使用&block传递给期望它们的方法参数列表末尾的语法。

def proc_to_block
  result = yield # only the return value of the block can be saved, not the block itself
  puts result
  result.class
end

block = Proc.new { 'inside the Proc' }

proc_to_block(&block)
# "inside the Proc"
# => String

虽然blockProc之间有一条双向的街道,但它们并不相同。请注意,要定义Proc,我们必须将block传递给Proc.new。严格来说,block只是传递给方法的一大块代码,该方法的执行延迟到显式调用。 Proc定义为block,其执行也会延迟到被调用,但它是一个真实的对象,就像其他任何对象一样。 block无法自行生存Proc

另一方面,blockblock of code有时会被随意用来指代由end终止的Ruby关键字所包含的任何谨慎的代码块:if...else...end,{ {1}},begin...rescue...enddef...endclass...endmodule...end。但这些本身并不是真正的块,只是表面上真的很像它们。通常它们也会延迟执行,直到满足某些条件。但是他们可以完全依靠自己,并且总是有回报价值。 Ruby-doc.org使用“表达式”更准确。

来自wikipedia

  

编程语言中的表达式是一个或多个的组合   更明确的值,常量,变量,运算符和函数   编程语言解释(根据其特定   优先权和关联规则)和计算产生(“to   返回“,在有状态的环境中”另一个值。

这就是为什么你可以做这样的事情

until...end

尝试使用块

return_value = if 'expression'
  true
end

return_value # => true

块本身不是表达式。它需要return_value = do true end # SyntaxError: (irb):24: syntax error, unexpected keyword_do_block # return_value = do # ^ 或转换为yield才能生存。当我们将一个块传递给一个不需要它的方法时会发生什么?

Proc

该块完全丢失,它消失,没有返回值,没有执行,就好像它从未存在过一样。它需要puts("indifferent") { "to blocks" } # "indifferent" # => nil 来完成表达式并产生返回值。

yield