Перевірте, чи клас Ruby є підкласом іншого класу


187

Я хотів би перевірити, чи успадковується клас від іншого класу, але, здається, не існує методу для цього.

class A
end

class B < A
end

B.is_a? A 
=> false

B.superclass == A
=> true

Тривіальною реалізацією того, чого я хочу, було б:

class Class
  def is_subclass_of?(clazz)
    return true if superclass == clazz
    return false if self == Object
    superclass.is_subclass_of?(clazz)
  end
end

але я б очікував, що це вже існує.


2
A.class #=> Class. Ось чому B.is_a? Aповертається помилково.
Вень

про щоkind_of?
акостадінов

1
kind_of?перевіряє, чи об’єкт є екземпляром класу. Чи не успадковується об’єкт від класу.
Плутанина

5
kind_of?псевдонімis_a?
coreyward

Відповіді:


355

Просто скористайтеся <оператором

B < A # => true
A < A # => false

або скористайтеся <=оператором

B <= A # => true
A <= A # => true

13
@Brian Тому що is_a?перекладається на примірник . Bне є примірником A, B.newхоча ( B.new.is_a? A # => true).
Марсель Джекверт

4
Хм, дивний синтаксис (не був би моїм першим здогадком), але дякую за пояснення!
Брайан Армстронг

2
Для документації див. Core API / Module / # < .
webwurst

2
Мої стосунки з любов'ю / ненавистю до Рубі продовжуються… Навіщо надавати іншу функцію оператору, який використовується для оголошення класових відносин І надавати два різні способи цього робити?
Бен Готов

4
@BenGotow - 1. Оскільки <не оператор, це метод. 2. Тому що <лише перевіряє підклас, а <= також включає self.
суперлюмінація

59

Також доступні:

B.ancestors.include? A

Це дещо відрізняється від (коротшої) відповіді, B < Aоскільки Bвона включена у B.ancestors:

B.ancestors
#=> [B, A, Object, Kernel, BasicObject]

B < B
#=> false

B.ancestors.include? B
#=> true

Бажано це чи ні, залежить від Вашого випадку використання.


24
Більш читабельний: B <= B(такий же результат, як B.ancestors.include? B).
Марсель Джекверт

Оновлення: Безпосередньо попереднє рішення працює з 1.9+, тоді як немає "предків"? в 1.9.

8
Це не бентежить людей, не знайомих із синтаксисом '<', і тому я вважаю за краще.
Асфанд Казі

2
@SimonLepkin Мабуть, не "на деякий час", якщо ви не можете відчути мікросекунди від. ;) Так, за лаштунками циклinclude? та <методи проходять через ланцюжок предків . Це робиться в C, так що, безумовно, швидше, ніж прокручування масиву Ruby ... але практично ці два мають бути нерозрізненими.
Фрогз

1
@JunanChakma Виходячи з того, як визначено англійське слово "предки", я погоджуюся, що повернене значення не повинно включати B. Але це робить. Документація методу говорить: "Повертає список модулів, включених / попередньо передбачених в моді ( включаючи сам мод )." (наголос мій). Я здогадуюсь, що він включає власний клас для зручності користування .include?, але це лише міркування з мого боку.
Фрогз
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.