为什么触发器操作符包含第二个条件?

时间:2013-09-03 19:29:18

标签: ruby flip-flop

以下代码使用触发器操作符。

(1..10).each {|x| print "#{x}," if x==3..x==5 }

为什么结果为3,4,5

我认为它应该是3,4

如教程中所述,此表达式在x == 3时变为true,并且在x == 5之前一直为真。如果评价为假,怎么会打印'5'?有人可以请我澄清一下吗?

6 个答案:

答案 0 :(得分:4)

“Ruby编程语言”中的重要链接是:

4.6.9.1 Boolean flip-flops

  

当..和...运算符用于条件语句时,例如if语句或   在循环中,例如while循环(有关条件和循环的更多信息,请参阅第5章),   它们不会创建Range对象。相反,他们创建了一种特殊的布尔值   表达式称为触发器。触发器表达式的计算结果为true或false,就像   比较和等式表达式。一个非常不寻常的事情   然而,触发器表达的价值取决于先前评估的价值 -   ations。这意味着触发器表达式具有与之相关的状态;它必须   记住以前的评估信息。因为它有状态,你会的   期待触发器成为某种对象。但它不是 - 它是一个Ruby表达式,而且   Ruby解释器在表达式的内部解析表示中存储它所需的状态(只是一个布尔值)。

     

考虑到这一背景,请考虑以下代码中的触发器。注意   代码中的第一个..创建一个Range对象。第二个创建触发器   表达式:

 (1..10).each {|x| print x if x==3..x==5 }
  

触发器由两个布尔表达式组成,它们与..运算符连接在一起   条件或循环的上下文。触发器表达式是假的,除非并且直到   左手表达式的计算结果为true。一旦表达成为现实,前   压力“翻转”成持久的真实状态。它仍然处于该状态,随后   在右边表达式求值为true之前,evaluatements返回true。当那个   发生时,触发器“翻转”回到持久的错误状态。随后的评估   表达式返回false,直到左手表达式再次变为true。   在代码示例中,重复评估触发器,x的值从1到   10.它以false状态开始,当x为1和2时评估为false   x == 3,触发器翻转为true并返回true。当x为时,它会继续返回true   然而,当x == 5时,触发器将翻转为假,并返回false   x的剩余值。结果是此代码打印345。

答案 1 :(得分:3)

..或触发器继承自Perl,它从AWK获得并在* nix中获取。它功能非常强大,但在你的特定用途中它是相当模糊的,并不是你想要的逻辑的好选择,特别是在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)/]) }

答案 2 :(得分:1)

  

我找到一段代码来说明触发器是如何工作的(只是在这段代码出现的同一本书中,希望它对那些像我一样有问题的人有帮助)

$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

答案 3 :(得分:0)

您在寻找专属系列吗?您可以使用三个点和cover?方法。

(1..10).each { |x| print "#{x}," if (3...5).cover?(x) }

在你的例子中打印3,4,5的原因是因为它表示如果x在3到5的范围内打印它。

答案 4 :(得分:0)

为了澄清@MurifoX的评论,触发器在x==5之前为真,因此在x==5时特别适用,但每次在此之后计算表达式时为假。因此,你仍然看到5被打印。

答案 5 :(得分:0)

触发器表达式的计算结果为true或false,就像比较和等式表达式一样。   然而,关于触发器表达的非常不寻常的事情是它的值取决于先前评估的值。这意味着触发器表达式具有与之相关的状态;它必须记住以前评估的信息。因为它有状态,你会的 期待触发器成为某种对象。但它不是 - 它是一个Ruby表达式,而且 Ruby解释器在其表达式的内部解析表示中存储它所需的状态(只是一个布尔值)。考虑到这一背景,请考虑以下代码中的触发器。注意第一个" .."在代码中创建一个Range对象。第二个创建触发器表达式:

(1..10).each {|x| print x if x==3..x==5 }

触发器由两个布尔表达式组成,它们与..运算符连接在一起 条件或循环的上下文。触发器表达式是假的,除非并且直到 左手表达式的计算结果为true。一旦该表达式变为真,表达式“翻转”为持久的真实状态。它仍然处于该状态,随后 在右边表达式求值为true之前,evaluatements返回true。当那个 发生时,触发器“翻转”回到持久的错误状态。随后的评估 表达式返回false,直到左手表达式再次变为true。 在代码示例中,重复评估触发器,x的值从1到 10.它以false状态开始,当x为1和2时评估为false。什么时候 x == 3,触发器翻转为true并返回true。当x为时,它会继续返回true 4和5。然而,当x == 5时,触发器将翻转为假,并返回false x的剩余值。结果是此代码打印345。