6

以下代码使用触发器运算符。

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

为什么是结果3,4,5

我认为应该是3,4

如教程中所述,此表达式在 时为真x == 3,并且在 之前一直为真x == 5。如果评估为假,如何打印“5”?谁能为我澄清一下?

4

6 回答 6

3

..或者触发器是从 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)/]) }
于 2013-09-03T21:38:46.987 回答
3

来自“The Ruby Programming Language”的重要链接是:

4.6.9.1 Boolean flip-flops

当 .. 和 ... 运算符用于条件语句(如 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。

于 2013-09-03T20:00:33.080 回答
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
于 2013-09-03T22:16:37.417 回答
0

触发器表达式的计算结果为 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 。

于 2014-12-24T11:01:33.667 回答
0

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

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

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

于 2013-09-03T19:40:02.583 回答
0

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

于 2013-09-03T19:43:22.593 回答