Почему диапазон с недопустимыми аргументами иногда не вызывает ошибку аргумента?
Следующий код вызывает ошибку аргумента:
n = 15
(n % 4 == 0)..(n % 3 == 0)
# => bad value for range (ArgumentError)
что я думаю, потому что это оценивает:
false..true
и различные типы классов используются в диапазоне: TrueClass
а также 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 ниже.
Тогда в первом случае (с возвращаемым значением def15) у нас есть только частичный диапазон без конечной части? Это так странно:)
2 ответа
В рубине if 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
Прежде всего, обратите внимание на следующие допустимые и недействительные литералы:
true..true # => valid
false..false # => valid
true..false # => invalid
false..true # => invalid
Таким образом, вопрос сводится к тому, почему выражения, которые оценивают false..true
а также true..false
становятся действительными, когда встроены в условие цикла. Согласно документации, литерал диапазона в состоянии цикла фактически не создает диапазон. Это скорее имеет особое значение, похожее на sed и awk. То есть истина начала диапазона инициирует цикл, а истина конца диапазона завершает его. Некоторые примеры найдены здесь.