请帮助我理解范围运算符...
和..
之间的差异,作为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]
答案 0 :(得分:4)
触发器(又名f / f)是有状态的运算符,它源自perl。
f / f运算符隐含在ruby的条件语句(if和三元)中,而不是范围 因此(1..5)是一个范围,但(1..5)是? 1:5是f / f。 f / f具有内部状态(是/否),由两个条件组成。 当第一个条件评估为true时,它会调整ON(状态变为true),而当第二个条件评估为true时,它会调整为OFF。 两个和三个虚线版本之间的区别在于 在第一个条件评估为true后,双点评估第二个条件,然后 三点不行。
两个点缀的版本是这样的:
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
让我们沿用amazing perl article,但以红宝石为例
两个点缀的示例:
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
P.S。范围和触发器是两个完全不同的运算符,您不应将它们混淆。
答案 1 :(得分:3)
触发器开关的概念实际上来自electronics。它的主要优点是它记住它的状态。将触发器布尔范围视为变量,存储布尔值。我们来看看下面的例子:
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
在您的第一个示例中,“条件”变为true
为4倍,并在3倍数时变回false
。在第二个示例中,条件变量未在12
上关闭,因为正确的范围边界(i%3
)被排除,因为它是一个3点范围。 / p>
希望这个例子不是太纠结。
答案 2 :(得分:1)
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
希望这有帮助。
答案 3 :(得分:0)
当在一个范围内使用双点时,它会创建一系列数字,这些数字最多可包含传入的最大数字。当使用三点时,它会创建一个范围,但不包括最大值号码传入。
所以:
(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