为什么触发器操作符包含第二个条件?
以下代码使用触发器操作符。
(1..10).each {|x| print "#{x}," if x==3..x==5 }
为什么结果3,4,5
?
我认为它应该是3,4
。
正如教程中所提到的,当x == 3
时,该表达式变为true,并且在x == 5
之前一直为真。 如果评估为假,如何打印’5’? 有人可以请我澄清一下吗?
“Ruby编程语言”的重要链接是:
4.6.9.1 Boolean flip-flops
当..和…运算符用于条件(例如if语句)或循环(例如while循环)时(有关条件和循环的更多信息,请参阅第5章),它们不会创建Range对象。 相反,他们创建了一种特殊的布尔表达式,称为触发器。 触发器表达式的计算结果为true或false,就像比较和等式表达式一样。 然而,关于触发器表达的一个非常不寻常的事情是它的值取决于先前评估的值。 这意味着触发器表达式具有与之相关的状态; 它必须记住以前的评估信息。 因为它有状态,你会期望触发器成为某种对象。 但它不是 – 它是一个Ruby表达式,并且Ruby解释器在其表达式的内部解析表示中存储它所需的状态(只是一个布尔值)。
考虑到这一背景,请考虑以下代码中的触发器。 请注意,代码中的第一个..创建一个Range对象。 第二个创建触发器表达式:
(1..10).each {|x| print x if x==3..x==5 }
触发器由在条件或循环的上下文中与…运算符连接的两个布尔表达式组成。 触发器表达式为false,除非并且直到左手表达式的计算结果为真。 一旦表达成为现实,表达“翻转”成持久的真实状态。 它保持在该状态,随后的评估将返回true,直到右侧表达式求值为true。 当发生这种情况时,触发器“翻转”回到持久的错误状态。 对表达式的后续计算返回false,直到左手表达式再次变为true。 在代码示例中,触发器被重复计算,x的值从1到10.它从假状态开始,当x是1和2时评估为假。当x == 3时,翻转 – 翻转翻转为true并返回true。 当x为4和5时,它继续返回true。然而,当x == 5时,触发器将返回false,并对x的剩余值返回false。 结果是此代码打印345。
..
或者触发器是从Perlinheritance的,它从AWK获得并在* nix中获得。 它function非常强大,但在您的特定用途中,它是相当模糊的,并不是您想要的逻辑的好选择,尤其是在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
因为正则表达式工作,所以可以创建一个复杂的模式来根据匹配从文件中检索行。 作为第一个,然后是第二个模式触发器,捕获线。 如果在文件的后面,另一行触发第一个模式,则再次发生捕获,直到第二个模式匹配。 它的function非常强大:
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)/]) }
我找到一段代码来说明触发器是如何工作的(就在这段代码出现的同一本书中,希望它对那些像我一样有问题的人有帮助)
$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
您在寻找专属系列吗? 你可以使用三个点和cover?
方法。
(1..10).each { |x| print "#{x}," if (3...5).cover?(x) }
在你的例子中它打印3,4,5的原因是因为它表示如果x在3到5的范围内打印它。
为了澄清@MurifoX的注释,触发器在x==5
之前是真的,因此在x==5
时是真的,但是每次在此之后计算表达式时它都是假的。 因此,你仍然看到5被打印。
触发器表达式的计算结果为true或false,就像比较和等式表达式一样。 然而,关于触发器表达的非常不寻常的事情是它的值取决于先前评估的值。 这意味着触发器表达式具有与之相关的状态; 它必须记住以前的评估信息。 因为它有状态,你会期望触发器成为某种对象。 但它不是 – 它是一个Ruby表达式,并且Ruby解释器在其表达式的内部解析表示中存储它所需的状态(只是一个布尔值)。 考虑到这一背景,请考虑以下代码中的触发器。 请注意,代码中的第一个“..”创建一个Range对象。 第二个创建触发器表达式:
(1..10).each {|x| print x if x==3..x==5 }
触发器由在条件或循环的上下文中与…运算符连接的两个布尔表达式组成。 触发器表达式为false,除非并且直到左手表达式的计算结果为真。 一旦该表达式变为真,表达式“翻转”为持久的真实状态。 它保持在该状态,随后的评估将返回true,直到右侧表达式求值为true。 当发生这种情况时,触发器“翻转”回到持久的错误状态。 对表达式的后续计算返回false,直到左手表达式再次变为true。 在代码示例中,对x的值从1到10重复计算触发器。它在false状态下开始,并在x为1和2时计算为false。 当x == 3时,触发器翻转为真并返回true。 当x为4和5时,它继续返回true。 然而,当x == 5时,触发器将翻转为假,并且对于x的剩余值返回false。 结果是此代码打印345。