繁体   English   中英

触发器红宝石中3点范围操作符和2点范围操作符之间的差异

[英]Difference between 3-dot-range operator and 2-dot-range operator in flip flop ruby

请帮助我理解范围运算符之间的区别.....作为Ruby中使用的“触发器”。

这是来自Pragmatic Programmers指南的示例:

a = (11..20).collect {|i| (i%4 == 0)..(i%3 == 0) ? i : nil}

返回:

[nil, 12, nil, nil, nil, 16, 17, 18, nil, 20]

也:

a = (11..20).collect {|i| (i%4 == 0)...(i%3 == 0) ? i : nil}

回:

[nil, 12, 13, 14, 15, 16, 17, 18, nil, 20]

触发器(又名f / f)是源自perl的有状态运算符。

f / f运算符隐含在ruby中的条件语句(if和ternary)而不是range中,因此(1..5)是一个范围但是(1..5)? 1:5是af / f。 f / f具有内部状态(真/假)并且由两个条件组成。 它在第一个条件评估为真时开启(状态变为真),在第二个条件评估为真时关闭。 两个和三个虚线版本之间的区别在于,双点在第一个评估为真后立即评估第二个条件,三点不评估。

两个虚线版本的工作原理如下:

A..B |
A -> false | State -> false
A -> true, B -> false | State -> true # notice how it checks both conditions
B -> false | State -> true
B -> true | State -> false
A -> false  | State -> false
A -> true, B -> true | State -> false

将它与三个虚线版本进行比较

A...B
A -> false | State -> false
A -> true | State -> true # three dotted version doesn't check second condition immediately
B -> false | State -> true
B -> true | State -> false
A -> false | State -> false
A -> true | State -> true

让我们沿着令人惊叹的perl文章,但在ruby中有例子

两个虚线示例:

DATA.each_line do |line|
  print "\t" if (line =~ /^start/ .. line =~ /^end/)
  print line
end

__END__
First line.
start
Indented line
end
Back to left margin

这打印:

First line.
    start
    Indented line
    end
Back to left margin

正如你所看到的那样 - f / f在第2行打开,在第4行打开。但它有一个微妙之处。 看一下这个:

DATA.each_line do |line|
  print "\t" if (line =~ /start/ .. line =~ /end/)
  print line
end
__END__
First line.
Indent lines between the start and the end markers
Back to left margin

这打印:

First line.
    Indent lines between the start and the end markers
Back to left margin

它在第2行打开并立即关闭。

让我们假设您不想在第一个操作符之后立即检查第二个操作符。 这是三点式f / f变得方便的地方。 看看下一个例子。

DATA.each_line do |line|
  print "\t" if (line =~ /start/ ... line =~ /end/)
  print line
end

__END__
First line.
Indent lines between the start and the end markers
So this is indented,
and this is the end of the indented block.
Back to left margin

哪个印刷品:

First line.
    Indent lines between the start and the end markers
    So this is indented,
    and this is the end of the indented block.
Back to left margin

你可以看到它在第2行打开,在第4行打开

现在让我们将它应用于您的示例

我写了一个小脚本来说明它的行为

def mod(n, i)
  result = i % n == 0
  puts "#{i} mod #{n} => #{result}"
  result
end

(11..20).each { |i|
  if (mod(4, i))...(mod(3, i)) # NOTE it's a three dotted version
    # NOTE that those puts show previous state, not the current one!
    puts true
  else
    puts false
  end
}

两个虚线结果:

11 mod 4 => false
false
12 mod 4 => true
12 mod 3 => true # Notice how it checks both conditions here
true
13 mod 4 => false
false
14 mod 4 => false
false
15 mod 4 => false
false
16 mod 4 => true
16 mod 3 => false
true
17 mod 3 => false
true
18 mod 3 => true
true
19 mod 4 => false
false
20 mod 4 => true
20 mod 3 => false
true

三点结果:

11 mod 4 => false
false
12 mod 4 => true
true
13 mod 3 => false
true
14 mod 3 => false
true
15 mod 3 => true # turns OFF here
true
16 mod 4 => true # and turns immediately ON here
true
17 mod 3 => false
true
18 mod 3 => true
true
19 mod 4 => false
false
20 mod 4 => true
true
=> 11..20

PS Range和flip / flop是两个完全不同的运算符,你不应该混淆它们。

触发开关的概念实际上来自电子产品 它的主要优点是它记住了它的状态。 将触发器布尔范围视为变量,存储布尔值。 我们来看看下面的例子:

1.upto(10).each do |i|
  puts i if (i%2==0)..(i%4==0)
end

        #                        vvvv   value of “hidden” state
2       # left range boundary  ⇨ true
3
4       # right range boundary ⇨ false, no 5 follows 
6       # left range boundary  ⇨ true
7
8       # right range boundary ⇨ false, no 9 follows 
10

在你的第一个例子中,“条件”对于4倍数变为true ,在3倍数时变为false 在第二个例子中,条件变量在12上没有关闭,因为它排除了右边界( i%3 ),因为它是一个3点范围。

希望这个例子不是太纠结。

Ruby中2点和3点之间的差异是包含。 例如

(1..100)
=> All numbers starting from 1 and ending at 100 INCLUDING 100

(1...100)
=> All numbers starting from 1 that are less than 100

(1..100).include?(100)
=> true

(1...100).include?(100)
=> false

希望这可以帮助。

当在一个范围内使用双点时,它会创建一系列数字,这些数字最多可包含传入的最大数量。当使用三点时,它会创建一个范围,该范围最多但不包括传入的最大数量。

所以:

 (1..5).each {| i | puts i} #will print 1,2,3,4,5

而:

(1...5).each {| i | puts i} #will print 1,2,3,4

暂无
暂无

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

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