Ruby ma uniwersalną ideę „ prawdy ” i „ fałszu ”.
Ruby ma mieć dwie klasy specyficzne dla Boolean obiektów, TrueClass
i FalseClass
, z pojedynczych przypadkach oznaczonych zmiennych specjalnych true
i false
, odpowiednio.
Jednak prawdomówność i fałsz nie ograniczają się do przypadków tych dwóch klas, koncepcja jest uniwersalna i dotyczy każdego obiektu w Rubim. Każdy przedmiot jest prawdomówny lub fałszywy . Zasady są bardzo proste. W szczególności tylko dwa obiekty są fałszywe :
nil
, pojedyncza instancjaNilClass
ifalse
, singleton wystąpienieFalseClass
Każdy inny przedmiot jest prawdziwy . Obejmuje to nawet obiekty, które są uważane za fałsz w innych językach programowania, takich jak
Reguły te są wbudowane w język i nie są definiowane przez użytkownika. Nie ma to_bool
niejawnej konwersji lub czegoś podobnego.
Oto cytat ze specyfikacji języka Ruby ISO :
6.6 Wartości logiczne
Obiekt jest klasyfikowany do obiektu prawdziwego lub fałszywego .
Tylko fałsz i zero są fałszywymi obiektami. false jest jedynym wystąpieniem klasy
FalseClass
(patrz 15.2.6), do którego odnosi się wyrażenie fałszywe (patrz 11.5.4.8.3). zero jest jedynym wystąpieniem klasyNilClass
(patrz 15.2.4), do którego ewaluuje wyrażenie zerowe (patrz 11.5.4.8.2).Przedmioty inne niż false i zero są klasyfikowane jako obiekty prawdziwe. true jest jedynym wystąpieniem klasy
TrueClass
(patrz 15.2.5), do którego odnosi się wyrażenie prawdziwe (patrz 11.5.4.8.3).
Plik wykonywalny Ruby / Spec wydaje się zgadzać :
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
Według tych dwóch źródeł zakładam, że Regexp
są one również zgodne z prawdą , ale według moich testów nie są to:
if // then 'Regexps are truthy' else 'Regexps are falsy' end
#=> 'Regexps are falsy'
Przetestowałem to na YARV 2.7.0-Preview1 , TruffleRuby 19.2.0.1 i JRuby 9.2.8.0 . Wszystkie trzy implementacje są ze sobą zgodne i nie zgadzają się ze Specyfikacją języka Ruby ISO i moją interpretacją Ruby / Spec.
Mówiąc dokładniej, Regexp
obiekty będące wynikiem oceny Regexp
literałów są fałszem , podczas gdy Regexp
obiekty, które są wynikiem jakiegoś innego wyrażenia, są prawdziwe :
r = //
if r then 'Regexps are truthy' else 'Regexps are falsy' end
#=> 'Regexps are truthy'
Czy to błąd lub pożądane zachowanie?
Regex.new("a")
jest prawdą.!!//
jest fałszywe, ale!!/r/
prawdziwe. Rzeczywiście dziwne.!!/r/
produkujefalse
dla mnie za pomocą (RVM) Ruby 2.4.1.//
inif // then
jest interpretowany jako test (skrót doif //=~nil then
) (który zawsze jest fałszem bez względu na wzorzec), a nie jako instancja Regexp.Odpowiedzi:
To nie jest błąd. Ruby przepisuje kod, żeby tak się stało
skutecznie staje się
Jeśli uruchamiasz ten kod w normalnym skrypcie (i nie korzystasz z
-e
opcji), powinieneś zobaczyć ostrzeżenie:Jest to prawdopodobnie nieco mylące przez większość czasu, dlatego pojawia się ostrzeżenie, ale może być przydatne w przypadku jednej linii z
-e
opcją. Na przykład możesz wydrukować wszystkie wiersze pasujące do danego wyrażenia regularnego z pliku za pomocą(Domyślny argument
print
to$_
również.)źródło
-n
,-p
,-a
i-l
opcje, jak również kilka metod jądra, które są dostępne tylko wtedy, gdy-n
albo-p
są używane (chomp
,chop
,gsub
isub
).NODE_LIT
z rodzajemT_REGEXP
. Ten, który zamieściłeś w odpowiedzi, dotyczy literału dynamicznegoRegexp
, tj.Regexp
Literału, który wykorzystuje interpolację, np/#{''}/
.$_
jako węzeł, który kompilator obsługuje normalnie, podczas gdy w przypadku statycznym wszystko jest obsługiwane przez kompilator. To dla mnie wstyd, ponieważ „hej, możesz zobaczyć, gdzie parsowane jest tutaj drzewo”, stanowi dobrą odpowiedź.Jest to wynik (o ile mogę powiedzieć) nieudokumentowanej funkcji języka ruby, co najlepiej tłumaczy ta specyfikacja :
Zasadniczo możesz traktować to
$_
jako „ostatni ciąg przeczytany przezgets
”Sprawiając, że sprawy stają się jeszcze bardziej zagmatwane,
$_
(wraz z$-
) nie jest zmienną globalną; ma zasięg lokalny .Po uruchomieniu skryptu Ruby,
$_ == nil
.Tak więc kod:
Jest interpretowany w następujący sposób:
... Który zwraca falsey.
Z drugiej strony, w przypadku wyrażenia nieliteralnego (np.
r = //
LubRegexp.new('')
), ta specjalna interpretacja nie ma zastosowania.//
jest prawdą; podobnie jak wszystkie inne przedmioty w rubinie oprócznil
ifalse
.O ile nie uruchomi skryptu ruby bezpośrednio w wierszu polecenia (tj. Z
-e
flagą), analizator ruby wyświetli ostrzeżenie przed takim użyciem:Państwo mogli skorzystać z tego zachowania w skrypcie, z czymś takim:
... Ale bardziej normalne byłoby przypisanie zmiennej lokalnej do wyniku
gets
i jawne sprawdzenie wyrażenia regularnego względem tej wartości.Nie znam żadnego przypadku użycia do wykonania tego sprawdzenia z pustym wyrażeniem regularnym, szczególnie gdy jest on zdefiniowany jako wartość dosłowna. Wyróżniony przez Ciebie wynik naprawdę zaskoczyłby większość deweloperów ruby.
źródło
!// #=> true
ma takie samo zachowanie i nie jest warunkowe. Nie mogłem znaleźć żadnego kontekstu logicznego (warunkowego lub nie), w którym zachowuje się on zgodnie z oczekiwaniami.!// ? true : false
Zwrotytrue
? Myślę, że to znowu ten sam punkt - jest interpretowany w następujący sposób:!(// =~ nil) ? true : false
$_ = 'hello world'
przed uruchomieniem powyższego kodu, powinieneś uzyskać inny wynik - ponieważ// =~ 'hello world'
, ale nie pasujenil
.!//
bez ocen warunkowych dotrue
. Podana specyfikacja dotyczyRegexp
literału w warunku, ale w tym przykładzie nie ma warunku, więc ta specyfikacja nie ma zastosowania.puts !//; $_ = ''; puts !//
- Przypuszczam, ponieważ parser rozwija je jak makro; niekoniecznie musi znajdować się w warunkowym?