Ruby: kind_of? против instance_of? против is_a?

488

В чем разница? Когда я должен использовать что? Почему их так много?

Клаудиу
источник
18
Что касается того, почему is_a?и kind_of?существует, и я думаю: это часть философии дизайна Руби. Python сказал бы, что должен быть только один способ что-то сделать; В Ruby часто используются синонимичные методы, поэтому вы можете использовать тот, который звучит лучше. Это вопрос предпочтений. Отчасти это может быть связано с влиянием японцев: мне сказали, что они будут использовать разные слова для одного и того же числа в зависимости от предложения, чтобы оно звучало лучше. Мац, возможно, перенес эту идею в свой языковой дизайн.
Натан Лонг
@NathanLong Я не думаю, что японские счетчики имеют много общего с этим; все языки имеют какое-то соглашение, и вы не можете заменять один счетчик на другой большую часть времени (например, вы не можете использовать счетчик цилиндров для плоских объектов; это просто неправильно). И это больше связано с семантикой, чем с эвфонией.
Кейси

Ответы:

622

kind_of?и is_a?являются синонимами.

instance_of?отличается от двух других тем, что возвращает только в том trueслучае, если объект является экземпляром этого точного класса, а не подклассом.

Пример:

  • "hello".is_a? Objectи "hello".kind_of? Objectвернуть, trueпотому что "hello"является Stringи Stringявляется подклассом Object.
  • Однако "hello".instance_of? Objectвозвращается false.
sepp2k
источник
77
Иногда это читается лучше. Подумайте, @honda.kind_of? Carа @person.is_a? AdministratorРуби все об эстетике. На самом деле, обратите внимание на грамматическую ошибку ... с активной поддержкой, которую вы можете написать:) @person.is_an? Administrator... Это могло бы сделать это ядром Ruby к настоящему моменту.
rfunduk
2
хех, это интересная причина ты можешь сломать это, ты? как вы можете переопределить, kind_of?но нет is_a??
Клавдиу
3
@thenduks, is_an?отсутствует в ruby-1.9.2-p0. @ Клаудиу, нет. is_a?это просто псевдонимkind_of? . Оба метода вызывают одну и ту же функцию c rb_obj_is_kind_of.
ma11hew28
9
@Matt: вы можете переопределить псевдоним без переопределения псевдонима. Так что да, вы можете переопределить kind_of?без переопределения is_a?.
sepp2k
4
Где этот is_an?метод ActiceSupport ?! Это не в текущей версии рельсов, и я не могу найти что-либо в Google о том, что это устарело.
Том Лорд
22

В чем разница?

Из документации:

- ( логическое )instance_of?(class)
Возвращает trueif objявляется экземпляром данного класса.

а также:

- ( булево ) is_a?(class)
- ( булево )kind_of?(class)
Возвращает trueif classявляется классом objили if classявляется одним из суперклассов objили модулей, включенных в obj.

Если это неясно, было бы неплохо узнать, что именно неясно, чтобы можно было улучшить документацию.

Когда я должен использовать что?

Никогда. Используйте вместо этого полиморфизм.

Почему их так много?

Я бы не назвал два "многие". Их два, потому что они делают две разные вещи.

Йорг Миттаг
источник
3
Я думаю, что моя путаница заключалась в том, что есть 3, и эти 2 просто делают одно и то же и имеют разные имена. Об использовании полиморфизма - я согласен, но стандартная библиотека ruby ​​полна использования каждого из них
Claudiu
4
Что вы подразумеваете под полиморфизмом? Это так же, как утка печатать?
Эндрю Гримм
2
Да, они одинаковы. Типирование утки - это форма полиморфизма.
SpaceGhost
3
Да, часто лучше сделать полиморфизм, но есть граничные случаи, когда вы действительно хотите знать, что у вас есть определенный класс, например, когда вы имеете дело с файлами.
Автомат
6

Рубиноподобнее спрашивать объекты, отвечают ли они на метод, который вам нужен, или нет, используя respond_to?. Это позволяет как минимальный интерфейс, так и реализацию незаметного программирования.

Конечно, это не всегда применимо, поэтому все еще есть возможность спросить о более консервативном понимании «типа», который является классом или базовым классом, используя методы, о которых вы спрашиваете.

kuonirat
источник
5
Это зависит от ситуации. Комментарии и блог могут отвечать на созданный_ответ. В такой ситуации is_a? более уместно ИМХО
пенковский
Это не имеет смысла, если бы вам нужно было отличить объект Comment от блога друг от друга, вы просто не использовали бы для этого созданный_т_. Это не исключает того, что вы могли бы написать метод, который принимает объект, который отвечает на созданный_каталог. Если ему больше ничего не нужно для своей работы, вы можете смело использовать его в комментариях, блогах или любой другой модели ActiveRecord.
Кингдон
3

Я также не назвал бы два многие ( is_a?и kind_of?это псевдонимы одного и того же метода), но если вы хотите увидеть больше возможностей, обратите ваше внимание на #classметод:

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
Борис Стиницкий
источник
1
Спасибо - я действительно спрашивал в общем смысле «какую информацию о типах времени выполнения можно собрать в Ruby и как» - и это дает достаточно примеров
Claudiu