我正在阅读Ruby中的if/elsif/else,在描述控件表达式的工作原理时,我在术语上遇到了一些差异。
在Ruby编程维基教科书中(着重号是加的(:
条件 Branch 获取测试表达式的结果,并根据测试表达式是真还是假执行代码块。
和
例如,if 表达式不仅确定是否执行从属代码块,而且还生成值本身。
但是,Ruby-doc.org 在定义中根本没有提到块:
最简单的 if 表达式有两个部分,一个 "test" 表达式和一个 "then"表达式。如果"test"表达式的计算结果为true,则计算"then"表达式。
通常,当我读到Ruby中的"块"时,它几乎总是在procs和lambdas的上下文中。例如,rubylearning.com 定义了一个块:
Ruby 块是一种对语句进行分组的方式,可能只出现在方法调用旁边的源中;该块与方法调用的最后一个参数(或参数列表的右括号(在同一行开始编写。
问题:
- 当谈论 Ruby 中的代码块时,我们是在谈论 传递给方法的代码组,或者我们只是 一般谈论一组代码? 有
- 没有办法轻松区分两者(并且有没有 两者之间的技术差异(?
这些问题的上下文:我想知道将条件中的代码称为块是否会让新的 Ruby 程序员在以后被引入块、过程和 lambda 时感到困惑。
TL;DRif...end
是一个表达式,而不是一个块
Ruby 中术语block
的正确用法是传递给介于do...end
或大括号{...}
之间的方法的代码。通过使用方法签名中的&block
语法,块可以并且经常隐式转换为方法中的Proc
。这个新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
(或lambda
,一种Proc
(可以通过在参数列表末尾使用&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
虽然block
和Proc
之间有一条双向的街道,但它们并不相同。请注意,要定义Proc
我们必须将block
传递给Proc.new
。严格来说,block
只是传递给方法的一段代码,该方法的执行被延迟到显式调用。Proc
是用block
定义的,它的执行也会延迟到被调用,但它是一个真正的对象,就像任何其他对象一样。block
不能靠自己生存,Proc
可以。
另一方面,block
或block of code
有时被随意地用来指代以end
结尾的Ruby关键字所包围的任何谨慎的代码块:if...else...end
,begin...rescue...end
,def...end
,class...end
,module...end
,until...end
。但这些本身并不是真正的块,只是在表面上真正类似于它们。通常,它们还会延迟执行,直到满足某些条件。但它们可以完全独立存在,并且始终具有返回值。Ruby-doc.org对"表达式"的使用更准确。
来自维基百科
编程语言中的表达式是 或 更明确的值、常量、变量、运算符和函数 编程语言解释(根据其特定 优先规则和关联规则(并计算产生("至 返回",在有状态环境中(另一个值。
这就是为什么你可以做这样的事情
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
才能完成表达式并生成返回值。
class Object
def puts(*args)
super
yield if block_given?
end
end
puts("mindful") { "of blocks" }
# "mindful"
# => "of blocks"