繁体   English   中英

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

[英]Why does a Flip-Flop operator include the second condition?

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

(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。

..或者触发器继承自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)/]) }

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

$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.它以假状态开始,并且当x是1和2时评估为假。 当x == 3时,触发器翻转为真并返回true。 当x为4和5时,它继续返回true。 然而,当x == 5时,触发器将翻转为假,并对x的剩余值返回false。 结果是此代码打印345。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM