9

以下代码导致参数错误:

n = 15
(n % 4 == 0)..(n % 3 == 0)
# => bad value for range (ArgumentError)

我认为这是因为它评估为:

false..true

TrueClass并且在 range:和中使用了不同类型的类FalseClass。但是,以下代码不会引发错误。这是为什么?Enumerable#collect抓到了吗?

(11..20).collect { |i| (i % 4 == 0)..(i % 3 == 0) ? i : nil }
# => no error

稍后添加: 如果fcn返回 15,则仅计算范围的前半部分

def fcn(x)
  puts x
  15
end

if  (fcn(1) % 4 == 0)..(fcn(2) % 3 == 0); end
# => 1

但是如果我们将返回值更改为 16 那么输入将是

# => 1
# => 2

这很奇怪,因为在这种情况下,表达式的计算结果为

true..false

根据下面sawa的回答,这种范围是无效的。

那么在第一种情况下(使用def的返回值 15)我们只有部分范围而没有结束部分?太奇怪了:)

4

2 回答 2

8

在 Rubyif start..finish中是一个触发器,一种用于编写快速而晦涩的脚本的特殊语法。它通常用于循环:

while input = gets
  puts "Processing #{input.inspect}" if input =~ /start/ .. input =~ /end/
end

当第一个条件为真时,整个条件在每次连续执行时都被视为真,直到第二个条件评估为真。您可以使用上面的脚本来了解这个想法。这是我的输入和输出:

foo
start
Processing "start\n"
foo
Processing "foo\n"
bar
Processing "bar\n"
end
Processing "end\n"
foo
bar
start
Processing "start\n"

请注意,如果条件未启动,Ruby 不会评估完成条件,因为这样做是没有用的。

尽管在循环之外使用它没有多大意义,但 Ruby 并没有限制它。

>> if nil..raise; :nothing_gonna_happen; end
=> nil
于 2012-09-12T13:09:41.427 回答
0

首先,请注意以下有效和无效的文字:

true..true # => valid
false..false # => valid
true..false # => invalid
false..true # => invalid

因此,问题归结为为什么表达式在嵌入循环条件时计算为有效false..truetrue..false根据文档,循环条件中的范围文字实际上并没有创建范围。它具有类似于 sed 和 awk 的特殊含义。也就是说,范围开始的真值启动循环,范围结束的真值终止循环。在这里找到一些例子。

于 2012-09-12T11:48:01.583 回答