Ruby: kind_of? vs. instance_of? kontra is_a?

487

Jaka jest różnica? Kiedy powinienem użyć które? Dlaczego jest ich tak wiele?

Claudiu
źródło
18
Jeśli chodzi o to, co jedno is_a?i drugie kind_of?: istnieje, jak sądzę, część filozofii projektowej Ruby. Python powiedziałby, że powinien być tylko jeden sposób na zrobienie czegoś; Ruby często ma synonimiczne metody, więc możesz użyć tej, która brzmi lepiej. To kwestia preferencji. Może to częściowo wynikać z wpływów Japonii: Powiedziano mi, że użyją innego słowa dla tej samej liczby w zależności od zdania, aby brzmiało to ładniej. Matz mógł przenieść tę ideę do swojego projektu językowego.
Nathan Long
@NathanLong Nie sądzę, że japońskie liczniki mają z tym wiele wspólnego; wszystkie języki są w pewnym stopniu zgodne i nie można przez większość czasu zastępować jednego licznika innym (np. nie można używać licznika cylindrycznego do płaskich obiektów; to po prostu źle). I ma więcej wspólnego z semantyką niż z eufonią.
Casey

Odpowiedzi:

621

kind_of?i is_a?są synonimami.

instance_of?różni się od pozostałych dwóch tym, że zwraca tylko truewtedy, gdy obiekt jest instancją tej właśnie klasy, a nie podklasą.

Przykład:

  • "hello".is_a? Objecti "hello".kind_of? Objectzwróć, trueponieważ "hello"jest a Stringi Stringjest podklasą Object.
  • Jednak "hello".instance_of? Objectpowraca false.
sepp2k
źródło
77
Czasami po prostu lepiej. Pomyśl @honda.kind_of? Cari @person.is_a? Administrator, Ruby jest o estetyce. W rzeczywistości zwróć uwagę na błąd gramatyczny ... przy aktywnym wsparciu, które możesz napisać:) @person.is_an? Administrator... To mogło już teraz stać się rdzeniem Rubiego.
rfunduk
2
heh, to ciekawy powód. czy możesz to przełamać? jak możesz nadpisać, kind_of?ale nie is_a??
Claudiu
3
@ thenduks, is_an?nie ma w ruby-1.9.2-p0. @Claudiu, no. is_a?jest tylko aliasemkind_of? . Obie metody powołać się na tej samej funkcji c, rb_obj_is_kind_of.
ma11hew28,
9
@Matt: Możesz zastąpić alias bez przesłaniania funkcji aliasu. Tak, możesz zastąpić kind_of?bez zastępowania is_a?.
sepp2k
4
Gdzie jest ta is_an?metoda ActiceSupport ?! Nie ma go w bieżącej wersji Railsów i nie mogę znaleźć niczego w Google na temat wycofania go.
Tom Lord
22

Jaka jest różnica?

Z dokumentacji:

- ( boolean )instance_of?(class)
Zwraca trueif objjest instancją danej klasy.

i:

- ( Boolean ) is_a?(class)
- ( Boolean )kind_of?(class)
Zwraca truejeśli classjest klasą objlub classjedną z nadklas objlub modułów zawartych w obj.

Jeśli nie jest to jasne, dobrze byłoby wiedzieć, co dokładnie jest niejasne, aby można było ulepszyć dokumentację.

Kiedy powinienem użyć które?

Nigdy. Zamiast tego użyj polimorfizmu.

Dlaczego jest ich tak wiele?

Nie nazwałbym dwóch „wieloma”. Są dwie, ponieważ robią dwie różne rzeczy.

Jörg W Mittag
źródło
3
Myślę, że moje zamieszanie polegało na tym, że są 3 i że 2 robią to samo i mają różne imiona. O korzystaniu z polimorfizmu - zgadzam się, ale rubinowa biblioteka standardowa jest pełna zastosowań każdego z nich
Claudiu,
4
Co rozumiesz przez polimorfizm? Czy to to samo, co pisanie kaczek?
Andrew Grimm,
2
Tak, są takie same. Pisanie kaczek jest formą polimorfizmu.
SpaceGhost,
3
Często lepiej jest robić polimorfizm, tak, ale są przypadki graniczne, w których naprawdę chcesz wiedzieć, że masz określoną klasę, na przykład gdy masz do czynienia z plikami.
Automatico
6

Bardziej rubinowe jest pytanie obiektów, czy odpowiadają na metodę, której potrzebujesz, czy nie, używając respond_to?. Pozwala to na minimalizację interfejsu i nieświadomego programowania.

Oczywiście nie zawsze ma to zastosowanie, dlatego nadal istnieje możliwość zapytania o bardziej konserwatywne rozumienie „typu”, czyli klasy lub klasy bazowej, przy użyciu metod, o które pytasz.

kuonirat
źródło
5
To zależy od sytuacji. Zarówno Komentarz, jak i Blog mogą odpowiadać na create_at. W takiej sytuacji jest? jest bardziej odpowiednie IMHO
penkovsky
To nie ma sensu, jeśli chcesz odróżnić od siebie komentarz i obiekt blogu, po prostu nie użyłbyś do tego create_at. To nie wyklucza, że ​​możesz napisać metodę, która pobiera obiekt, który odpowiada na create_at. Jeśli nie potrzebuje niczego innego do wykonania swojej pracy, możesz bezpiecznie użyć go w komentarzu, blogu lub całkiem innym modelu ActiveRecord.
Kingdon,
3

Nie nazwałbym też dwóch wielu ( is_a?i kind_of?są to aliasy tej samej metody), ale jeśli chcesz zobaczyć więcej możliwości, zwróć uwagę na #classmetodę:

A = Class.new
B = Class.new A

a, b = A.new, B.new
b.class < A # true - means that b.class is a subclass of A
a.class < B # false - means that a.class is not a subclass of A
# Another possibility: Use #ancestors
b.class.ancestors.include? A # true - means that b.class has A among its ancestors
a.class.ancestors.include? B # false - means that B is not an ancestor of a.class
Boris Stitnicky
źródło
1
Dzięki - rzeczywiście pytałem w ogólnym sensie „jakie informacje o typie wykonawczym można zebrać w Ruby i w jaki sposób” - i to daje wiele przykładów
Claudiu