Почему диапазон с недопустимыми аргументами иногда не вызывает ошибку аргумента?

Следующий код вызывает ошибку аргумента:

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. То есть истина начала диапазона инициирует цикл, а истина конца диапазона завершает его. Некоторые примеры найдены здесь.

Другие вопросы по тегам