Во время выполнения дженерики не являются reified . Это означает, что информация отсутствует во время выполнения.
Добавление дженериков в Java при сохранении обратной совместимости было де-силовым (вы можете ознакомиться с оригинальной статьей: Создание будущего безопасный для прошлого: добавление универсальности к языку программирования Java ).
Существует богатая литература по этому вопросу, а некоторые люди недовольны текущим состоянием , некоторые говорят, что на самом деле это приманка , и в этом нет никакой реальной необходимости. Вы можете прочитать обе ссылки, я нашел их довольно интересными.
Нормальный способ сделать перечисления в Lisp состоит в том, чтобы использовать символы. Символы интернируются (замененный указателями на их записи в таблице символов), таким образом, они с такой скоростью, как целые числа и столь же читаемы как перечислимые константы на других языках.
Поэтому, где в C Вы могли бы записать:
enum { apple, orange, banana, };
В Lisp можно просто использовать 'apple
, 'orange
и 'banana
непосредственно.
при необходимости в перечислимом тип , затем можно определить один с [1 110] deftype
:
(deftype fruit () '(member apple orange banana))
и затем можно использовать тип fruit
в declare
, typep
, typecase
и так далее, , и можно записать родовые функции, которые специализируются на том типе .
Например, Вы хотите назвать размеры шрифта:
(defconstant +large+ 3)
(defconstant +medium+ 2)
(defconstant +small+ 1)
Вы могли записать макрос для создания этого короче.
Выше постоянных определений обычно пишутся ТОЛЬКО, когда эти числа должны быть переданы некоторому внешнему коду не-Lisp.
Иначе можно было бы просто использовать символы ключевого слова:: большой: носитель и: маленький.
можно протестировать их с EQ и всем, что использует некоторый тест для равенства.
(let ((size :medium))
(ecase size
(:small ...)
(:medium ...)
(:large ...)))
можно также записать методы для него:
(defmethod draw-string (message x y (size (eql :large))) ...)
, Как упомянуто Вы могли определить тип набора:
(deftype size () '(member :small :medium :large))
Тогда можно проверить, имеет ли что-то любой тех:
(let ((my-size :medium))
(check-type my-size size))
Выше сигнализировал бы об ошибке, если мой-размер не является одним из: маленький: носитель или: большой.
можно также использовать тип в форме defclass:
(defclass vehicle ()
((width :type size :initarg :width)))
Теперь Вы создали бы объекты как здесь:
(make-instance 'vehicle :width :large)
Некоторые реализации языка Common LISP проверят при установке слота на некоторое недопустимое значение.
, Если Вы теперь создаете объекты механизма класса, слоты будут одним из: большой: носитель или: маленький. При рассмотрении объекта в отладчике инспекторе или некотором другом инструменте, Вы будете видеть символьные имена а не 1, 2 или 3 (или безотносительно значений, которые Вы обычно использовали бы).
Это - часть стиля Lisp: используйте символьные имена, если это возможно. Используйте символы с числовыми значениями только в интерфейсном коде к внешним функциям (как вызов внешнего кода C, который использует перечисления).
Перечисления избыточны для Lisp, при этом причина состоит в том, что все символы являются своими собственными идентификационными данными, таким образом, можно просто использовать их, например:
[dsm@localhost:~]$ clisp -q
[1]> (setf x 'some) ;'
SOME
[2]> (eq x 'some) ;'
T
[3]>