У Руби есть универсальное представление о « правдивости » и « ложности ».
Рубин делает два конкретных классов для объектов Boolean, TrueClass
и FalseClass
, с одноплодными случаями , обозначенных специальными переменными true
и false
, соответственно.
Однако правдивость и ложность не ограничиваются экземплярами этих двух классов, концепция универсальна и применима к каждому объекту в Ruby. Каждый объект является либо правдивым, либо ложным . Правила очень просты. В частности, только два объекта являются ложными :
nil
, единичный случайNilClass
иfalse
единичный случайFalseClass
Каждый другой объект является truthy . Это включает даже объекты, которые считаются ложными в других языках программирования, таких как
Эти правила встроены в язык и не определяются пользователем. Не существует to_bool
неявного преобразования или чего-либо подобного.
Вот цитата из спецификации языка Ruby ISO :
6.6 Булевы значения
Объект классифицируется как истинный объект или ложный объект .
Только ложь и ноль являются ложными объектами. false - единственный экземпляр класса
FalseClass
(см. 15.2.6), для которого оценивается ложное выражение (см. 11.5.4.8.3). nil - единственный экземпляр классаNilClass
(см. 15.2.4), для которого оценивается nil-выражение (см. 11.5.4.8.2).Объекты, отличные от false и nil , классифицируются как истинные объекты. Значение true является единственным экземпляром класса
TrueClass
(см. 15.2.5), для которого оценивается выражение true (см. 11.5.4.8.3).
Исполняемый Ruby / Spec, похоже, согласен :
it "considers a non-nil and non-boolean object in expression result as true" do if mock('x') 123 else 456 end.should == 123 end
Согласно этим двум источникам, я бы предположил, что Regexp
s также правдивы , но, согласно моим тестам, они не являются:
if // then 'Regexps are truthy' else 'Regexps are falsy' end
#=> 'Regexps are falsy'
Я проверял это на YARV 2.7.0-preview1 , TruffleRuby 19.2.0.1 и JRuby 9.2.8.0 . Все три реализации согласуются друг с другом и не соответствуют спецификации языка Ruby ISO и моей интерпретации Ruby / Spec.
Точнее говоря, Regexp
объекты, которые являются результатом вычисления Regexp
литералов, являются ложными , тогда как Regexp
объекты, которые являются результатом некоторых других выражений, являются правдивыми :
r = //
if r then 'Regexps are truthy' else 'Regexps are falsy' end
#=> 'Regexps are truthy'
Это ошибка или желаемое поведение?
Regex.new("a")
это правда.!!//
ложно, но!!/r/
верно. Странно действительно.!!/r/
производитfalse
для меня использование (RVM) Ruby 2.4.1.//
вif // then
интерпретируется как тест (сокращение дляif //=~nil then
) (это всегда ложно, независимо от шаблона), а не как экземпляр Regexp.Ответы:
Это не ошибка Происходит то, что Ruby переписывает код так, чтобы
эффективно становится
Если вы запускаете этот код в обычном скрипте (и не используете
-e
опцию), вы должны увидеть предупреждение:Это, вероятно, несколько сбивает с толку большую часть времени, поэтому и дается предупреждение, но может быть полезно для одной строки, используя
-e
опцию. Например, вы можете напечатать все строки, соответствующие заданному регулярному выражению, из файла с( По умолчанию аргумент для
print
это$_
так.)источник
-n
,-p
,-a
и-l
опционы, а также несколько методов ядра, которые доступны только тогда , когда-n
или-p
используются (chomp
,chop
,gsub
иsub
).NODE_LIT
с типомT_REGEXP
. Тот, который вы разместили в своем ответе, предназначен для динамическогоRegexp
литерала , то естьRegexp
литерала, который использует интерполяцию, например/#{''}/
.$_
в качестве узла, который компилятор обрабатывает как обычно, в то время как в статическом случае все это обрабатывается компилятор. Это позор для меня, потому что «эй, вы можете видеть, где дерево синтаксического анализа переписано здесь» делает хороший ответ.Это результат (насколько я могу судить) недокументированной возможности языка ruby, которая лучше всего объясняется этой спецификацией :
Вы можете вообще думать
$_
как "последняя строка, прочитаннаяgets
"Чтобы сделать вещи еще более запутанными,
$_
(наряду с$-
) не является глобальной переменной; это имеет локальную сферу применения .Когда запускается скрипт ruby
$_ == nil
.Итак, код:
Интерпретируется как:
... который возвращает фальси.
С другой стороны, для не буквального регулярного выражения (например,
r = //
илиRegexp.new('')
) это специальное толкование не применяется.//
правда; как и все остальные объекты в ruby, кромеnil
иfalse
.Если сценарий ruby не запущен непосредственно в командной строке (то есть с
-e
флагом), анализатор ruby будет отображать предупреждение против такого использования:Вы можете использовать это поведение в скрипте, например:
... Но было бы более нормально назначить локальную переменную результату
gets
и выполнить проверку регулярного выражения по этому значению явно.Я не знаю ни одного варианта использования для выполнения этой проверки с пустым регулярным выражением, особенно когда оно определено как буквальное значение. Выделенный вами результат действительно застал бы врасплох большинство разработчиков ruby.
источник
!// #=> true
имеет такое же поведение и не является условным. Я не смог найти никакого логического контекста (условного или нет), где он ведет себя как ожидалось.!// ? true : false
возвратtrue
? Я думаю, что это то же самое снова - это интерпретируется как:!(// =~ nil) ? true : false
$_ = 'hello world'
перед запуском вышеуказанного кода, то вы должны получить другой результат - потому что// =~ 'hello world'
, но не совпадаетnil
.!//
без условных оценокtrue
. Указанная вами спецификация относится кRegexp
литералу в условном выражении, но в этом примере условного обозначения не существует, поэтому данная спецификация не применяется.puts !//; $_ = ''; puts !//
- я полагаю, потому что синтаксический анализатор расширяет его как макрос; это не обязательно должно быть внутри условного?