Typy klas Ruby i instrukcje case


138

Jaka jest różnica pomiędzy

case item.class
when MyClass
  # do something here
when Array
  # do something different here
when String
  # do a third thing
end

i

case item.class
when MyClass.class
  # do something here
when Array.class
  # do something different here
when String.class
  # do a third thing
end

Z jakiegoś powodu pierwsza z nich czasami działa, a druga nie, a innym razem druga działa, a pierwsza nie. Czemu? Który z nich jest „właściwym” sposobem, aby to zrobić?


1
Ciąg jest klasą. Klasa klasy to Class.
Volte

Zauważ, że MyClass === objużywa metody Module # === do sprawdzenia, czy objjest to wystąpienie MyClass.
sergio 郝海东 冠状 病 六四 事件 法轮功

Odpowiedzi:


237

Musisz użyć:

case item
when MyClass
...

Miałem ten sam problem: Jak wyłapać klasę Errno :: ECONNRESET w "przypadku kiedy"?


1
Dzięki! Przepraszam, że oszukuję (lub trochę oszukuję), ale kilka wyszukiwań nie przyniosło tego poprzedniego pytania. Wygląda na to, że użycie === w opisie przypadku jest dość powszechnym problemem, teraz, gdy widzę, na tym polega problem. Prawdopodobnie powinno być to częściej podkreślane w tutorialach i tym podobnych (ale założę się, że wielu autorów tutoriali również nie jest tego świadomych).
Daisy Sophia Hollman

4
Ostrzeżenie, o którym nie wspomniano, jeśli używasz ActiveRecord. Metoda ActiveRecord === w porównaniach klas używa .is_a?, Co oznacza, że ​​podklasy klasy będą zwracane jako prawda w instrukcji case. github.com/rails/rails/blob/…
Jeremy Baker

63

Tak, Nakilon ma rację, musisz wiedzieć, jak działa operator trzech równych === na obiekcie podanym w whenklauzuli. W Ruby

case item
when MyClass
...
when Array
...
when String
...

jest naprawdę

if MyClass === item
...
elsif Array === item
...
elsif String === item
...

Zrozum, że przypadek wywołuje metodę trzech równych ( MyClass.===(item)na przykład) i tę metodę można zdefiniować tak, aby robiła, co chcesz, a następnie możesz użyć instrukcji case z precyzją


1
Jeśli arr = []zauważyłem, że if Array === arrto oceni jako prawda, ale if arr === Arrayoceni jako fałsz. Czy ktoś może pomóc wyjaśnić?
Daniel

5
=== to po prostu metoda, którą można zdefiniować tak, aby robiła to, czego oczekuje projektant klasy. Pamiętaj też, że a === b naprawdę oznacza a. === b, więc jeśli zamienisz a i b, możesz uzyskać inne zachowanie. Nie ma gwarancji, że === jest przemienne. W rzeczywistości Array === Array jest fałszywe, ale Object === Object jest true, więc Array redefiniuje semantykę ===.
Fred


5

W Rubim nazwa klasy jest stałą, która odnosi się do obiektu typu Classopisującego określoną klasę. Oznacza to, że mówienie MyClassw Rubim jest równoznaczne z mówieniem MyClass.classw Javie.

obj.classjest obiektem typu Classopisującym klasę obj. Jeśli obj.classtak MyClass, to objzostał utworzony przy użyciu MyClass.new(z grubsza mówiąc). MyClassto obiekt typu, Classktóry opisuje dowolny obiekt utworzony za pomocą MyClass.new.

MyClass.classto klasa MyClassobiektu (jest to klasa obiektu typu Classopisująca dowolny obiekt utworzony za pomocą MyClass.new). Innymi słowy MyClass.class == Class.


1

To zależy od charakteru twojej itemzmiennej. Jeśli jest to instancja obiektu, np

t = 5

następnie

t.class == Fixnum

ale jeśli jest to klasa sama w sobie np

t = Array

wtedy będzie to Classobiekt, więc

t.class == Class

EDYCJA : zapoznaj się z Jak złapać klasę Errno :: ECONNRESET w "przypadku kiedy"? jak stwierdził Nakilon, ponieważ moja odpowiedź może być błędna.


W Rubim wszystko jest „instancją obiektu”.
Eric Duminil
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.