在 Ruby 中,if/elsif/else 语句的从属块是否与作为参数传递的 'block' 相同?
In Ruby, is an if/elsif/else statement's subordinate block the same as a 'block' that is passed as a parameter?
我正在阅读 Ruby 中关于 if/elsif/else 的内容,并且在描述控制表达式的工作原理时 运行 发现了一些术语上的差异。
在Ruby Programming Wikibooks(强调已加):
A conditional Branch takes the result of a test expression and executes a block of code depending whether the test expression is true or false.
和
An if expression, for example, not only determines whether a subordinate block of code will execute, but also results in a value itself.
Ruby-doc.org,然而,在定义中根本没有提到块:
The simplest if expression has two parts, a “test” expression and a “then” expression. If the “test” expression evaluates to a true then the “then” expression is evaluated.
通常,当我在 Ruby 中阅读有关 'blocks' 的内容时,它几乎总是在过程和 lambda 的上下文中。例如,rubylearning.com定义了一个块:
A Ruby block is a way of grouping statements, and may appear only in the source adjacent to a method call; the block is written starting on the same line as the method call's last parameter (or the closing parenthesis of the parameter list).
问题:
- 当谈论 Ruby 中的代码块时,我们是在谈论
传递给方法的一组代码,或者我们只是
泛泛而谈的一组代码?
- 有没有办法轻松区分两者(并且有没有
两者之间的技术差异)?
这些问题的背景:我想知道将条件语句内部的代码称为 块 是否会让新的 Ruby 程序员感到困惑块、过程和 lambda。
TL;DR if...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
的一种类型)可以 "expanded" 放入块中,并传递给需要它们的方法,方法是使用 &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
s 和 Proc
s 之间有一条双向街道,但它们并不相同。请注意,要定义 Proc
,我们必须将 block
传递给 Proc.new
。严格来说 block
只是传递给方法的代码块,该方法的执行被推迟到明确调用为止。 Proc
是用 block
定义的,它的执行也被推迟到被调用时,但它和其他对象一样是一个真正的对象。 block
不能靠自己生存,Proc
可以。
另一方面,block
或 block of code
有时被随意用来指代由 Ruby 以 end
结尾的关键字包围的任何谨慎的代码块:if...else...end
、begin...rescue...end
、def...end
、class...end
、module...end
、until...end
。但这些并不是真正的块,就其本身而言,只是在表面上真正类似于它们。通常他们也会推迟执行,直到满足某些条件。但它们可以完全独立,并且始终具有 return 值。 Ruby-doc.org对"expression"的使用更准确。
An expression in a programming language is a combination of one or
more explicit values, constants, variables, operators, and functions
that the programming language interprets (according to its particular
rules of precedence and of association) and computes to produce ("to
return", in a stateful environment) another value.
这就是为什么你可以这样做
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
块完全丢失,它消失了,没有 return 值,没有执行,就好像它从未存在过一样。它需要 yield
来完成表达式并产生 return 值。
class Object
def puts(*args)
super
yield if block_given?
end
end
puts("mindful") { "of blocks" }
# "mindful"
# => "of blocks"
我正在阅读 Ruby 中关于 if/elsif/else 的内容,并且在描述控制表达式的工作原理时 运行 发现了一些术语上的差异。
在Ruby Programming Wikibooks(强调已加):
A conditional Branch takes the result of a test expression and executes a block of code depending whether the test expression is true or false.
和
An if expression, for example, not only determines whether a subordinate block of code will execute, but also results in a value itself.
Ruby-doc.org,然而,在定义中根本没有提到块:
The simplest if expression has two parts, a “test” expression and a “then” expression. If the “test” expression evaluates to a true then the “then” expression is evaluated.
通常,当我在 Ruby 中阅读有关 'blocks' 的内容时,它几乎总是在过程和 lambda 的上下文中。例如,rubylearning.com定义了一个块:
A Ruby block is a way of grouping statements, and may appear only in the source adjacent to a method call; the block is written starting on the same line as the method call's last parameter (or the closing parenthesis of the parameter list).
问题:
- 当谈论 Ruby 中的代码块时,我们是在谈论 传递给方法的一组代码,或者我们只是 泛泛而谈的一组代码?
- 有没有办法轻松区分两者(并且有没有 两者之间的技术差异)?
这些问题的背景:我想知道将条件语句内部的代码称为 块 是否会让新的 Ruby 程序员感到困惑块、过程和 lambda。
TL;DR if...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
的一种类型)可以 "expanded" 放入块中,并传递给需要它们的方法,方法是使用 &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
s 和 Proc
s 之间有一条双向街道,但它们并不相同。请注意,要定义 Proc
,我们必须将 block
传递给 Proc.new
。严格来说 block
只是传递给方法的代码块,该方法的执行被推迟到明确调用为止。 Proc
是用 block
定义的,它的执行也被推迟到被调用时,但它和其他对象一样是一个真正的对象。 block
不能靠自己生存,Proc
可以。
另一方面,block
或 block of code
有时被随意用来指代由 Ruby 以 end
结尾的关键字包围的任何谨慎的代码块:if...else...end
、begin...rescue...end
、def...end
、class...end
、module...end
、until...end
。但这些并不是真正的块,就其本身而言,只是在表面上真正类似于它们。通常他们也会推迟执行,直到满足某些条件。但它们可以完全独立,并且始终具有 return 值。 Ruby-doc.org对"expression"的使用更准确。
An expression in a programming language is a combination of one or more explicit values, constants, variables, operators, and functions that the programming language interprets (according to its particular rules of precedence and of association) and computes to produce ("to return", in a stateful environment) another value.
这就是为什么你可以这样做
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
块完全丢失,它消失了,没有 return 值,没有执行,就好像它从未存在过一样。它需要 yield
来完成表达式并产生 return 值。
class Object
def puts(*args)
super
yield if block_given?
end
end
puts("mindful") { "of blocks" }
# "mindful"
# => "of blocks"