以下代码使用触发器运算符。
(1..10).each {|x| print "#{x}," if x==3..x==5 }
为什么是结果3,4,5
?
我认为应该是3,4
。
如教程中所述,此表达式在 时为真x == 3
,并且在 之前一直为真x == 5
。如果评估为假,如何打印“5”?谁能为我澄清一下?
..
或者触发器是从 Perl 继承的,Perl 从 AWK 获得它并在 *nix 中使用 sed。它非常强大,但在您的特定用途中它相当晦涩,对于您想要的逻辑来说不是一个好的选择,尤其是在 Ruby 中。而是使用:
(1..10).each {|x| puts x if (3..5) === x }
哪个输出:
3
4
5
也就是说,当您需要从文件中提取一系列行时,它非常强大:
File.foreach('/usr/share/dict/propernames') { |li| puts li if ($. == 5 .. $. == 7) }
哪个输出:
Agatha
Ahmed
Ahmet
Perl 允许使用仅使用当前读取行 (AKA) 的行号的更简洁的表达式,$.
但 Ruby 不支持。
还可以选择使用正则表达式,其行为与之前的比较类似:
File.foreach('/usr/share/dict/propernames') { |li| puts li if (li[/^Wa/] .. li[/^We/]) }
哪个输出:
Wade
Walt
Walter
Warren
Wayne
Wendell
因为正则表达式有效,所以可以创建一个复杂的模式来根据匹配从文件中检索行。作为第一个,然后是第二个模式触发,线被捕获。如果稍后在文件中,另一行触发了第一个模式,则捕获将再次发生,直到第二个模式匹配。它非常强大:
File.foreach('/usr/share/dict/propernames') { |li| puts li if (
li[/^Am/] .. li[/^An/] or
li[/^Wa/] .. li[/^We/]
)
}
哪个输出:
Amanda
Amarth
Amedeo
Ami
Amigo
Amir
Amos
Amy
Anatole
Wade
Walt
Walter
Warren
Wayne
Wendell
或者,对于我们会说晦涩代码的朋友:
File.foreach('/usr/share/dict/propernames') { |li| puts li if (li[/^(?:Am|Wa)/] .. li[/^(?:An|We)/]) }
来自“The Ruby Programming Language”的重要链接是:
当 .. 和 ... 运算符用于条件语句(如 if 语句)或循环(如 while 循环)时(有关条件和循环的更多信息,请参见第 5 章),它们不会创建 Range 对象。相反,他们创建了一种特殊的布尔表达式,称为触发器。触发器表达式的计算结果为真或假,就像比较和相等表达式一样。然而,触发器表达式的异常之处在于它的值取决于先前评估的值。这意味着触发器表达式具有与之关联的状态;它必须记住有关先前评估的信息。因为它有状态,所以你会认为触发器是某种对象。但它不是——它是一个 Ruby 表达式,
考虑到这一背景,请考虑以下代码中的触发器。请注意,代码中的第一个 .. 创建了一个 Range 对象。第二个创建触发器表达式:
(1..10).each {|x| print x if x==3..x==5 }
在条件或循环的上下文中,触发器由两个用 .. 运算符连接的布尔表达式组成。触发器表达式为假,除非且直到左手表达式的计算结果为真。一旦该表达式变为真,该表达式“翻转”为持久的真状态。它保持在那个状态,随后的计算返回真,直到右边的表达式计算为真。当这种情况发生时,触发器会“翻转”回持续的错误状态。表达式的后续计算返回 false,直到左侧表达式再次变为 true。在代码示例中,触发器被重复评估,x 的值从 1 到 10。它从 false 状态开始,当 x 为 1 和 2 时评估为 false。当 x==3 时,触发器flop 翻转为 true 并返回 true。当 x 为 4 和 5 时,它继续返回真。然而,当 x==5 时,触发器返回假,并为剩余的 x 值返回假。结果是这段代码打印了 345。
我找到了一段代码来说明触发器的工作原理(就在这段代码出现的同一本书中,希望它对像我一样有同样问题的人有所帮助)
$state = false # Global storage for flip-flop state
def flipflop(x) # Test value of x against flip-flop
if !$state # If saved state is false
result = (x == 3) # Result is value of lefthand operand
if result # If that result is true
$state = !(x == 5) # Then saved state is not of the righthand operand
end
result # Return result
else # Otherwise, if saved state is true
$state = !(x == 5) # Then save the inverse of the righthand operand
true # And return true without testing lefthand
end
end
触发器表达式的计算结果为 true 或 false ,就像比较和相等表达式一样。然而,触发器表达式的异常之处在于它的值取决于先前评估的值。这意味着触发器表达式具有与之关联的状态;它必须记住有关先前评估的信息。因为它有状态,所以你会认为触发器是某种对象。但它不是——它是一个 Ruby 表达式,Ruby 解释器将它需要的状态(只是一个布尔值)存储在表达式的内部解析表示中。考虑到这一背景,请考虑以下代码中的触发器。请注意,代码中的第一个“..”创建了一个 Range 对象。第二个创建触发器表达式:
(1..10).each {|x| print x if x==3..x==5 }
在条件或循环的上下文中,触发器由两个用 .. 运算符连接的布尔表达式组成。触发器表达式为 false ,除非且直到左侧表达式的计算结果为 true 。一旦该表达式变为 true ,表达式“翻转”为持久的 true 状态。它保持在那个状态,随后的计算返回 true ,直到右边的表达式计算为 true 。当这种情况发生时,触发器会“翻转”回持续的错误状态。表达式的后续计算返回 false,直到左侧表达式再次变为 true。在代码示例中,触发器被重复评估,x 的值从 1 到 10。它从 false 状态开始,并在 x 为 1 和 2 时评估为 false。当 x==3 时,触发器翻转为 true 并返回 true 。当 x 为 4 和 5 时,它继续返回 true。但是,当 x==5 时,触发器将返回 false ,并为 x 的剩余值返回 false。结果是此代码打印 345 。
您在寻找独家系列吗?您可以使用三个点和cover?
方法。
(1..10).each { |x| print "#{x}," if (3...5).cover?(x) }
在您的示例中它打印 3,4,5 的原因是因为它说如果 x 在 3 到 5 的范围内打印它。
为了澄清@MurifoX 的评论,触发器在 之前为真x==5
,因此特别是在 时为真x==5
,但在此之后每次评估表达式时为假。因此,您仍然看到 5 正在打印。