Common Lisp相当于C枚举

时间:2009-02-23 16:31:26

标签: enums lisp common-lisp

我最近正在尝试学习一些Lisp(Common Lisp),我想知道是否有一种方法可以为常数提供一个名称,就像你可以通过枚举在C中做的那样。

我不需要枚举的完整功能集。最后,我只想拥有快速的可读代码。

我已经尝试过全局和小功能,但总会带来性能降低。只需将数字插入代码中总是更快。

3 个答案:

答案 0 :(得分:21)

在Lisp中执行枚举的常规方法是使用符号。符号被实现(用符号表中的条目指针替换),因此它们与整数一样快,并且与其他语言中的枚举常量一样可读。

所以在C中你可能会写:

enum {
   apple,
   orange,
   banana,
};

在Lisp中,您可以直接使用'apple'orange'banana

如果您需要枚举的类型,那么您可以使用deftype定义一个:

(deftype fruit () '(member apple orange banana))

然后您可以使用fruitdeclaretypep等类型typecase,等等,,您可以编写专门针对该类型的泛型函数输入

答案 1 :(得分:15)

例如,您想命名字体大小:

(defconstant +large+ 3)
(defconstant +medium+ 2)
(defconstant +small+ 1)

你可以编写一个宏来缩短它。

以上常量定义通常仅在需要将这些数字传递给某些外部非Lisp代码时才会写入。

否则只会使用关键字符号:: large,:medium和:small。

您可以使用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))

如果my-size不是以下之一,则上面会发出错误:small,:medium或:large。

您还可以使用defclass形式的类型:

(defclass vehicle ()
   ((width :type size :initarg :width)))

现在你要创建像这样的对象:

(make-instance 'vehicle :width :large)

一些Common Lisp实现将检查何时将插槽设置​​为某个非法值。

如果您现在创建类车辆的对象,则插槽将是以下之一:large,:medium或:small。如果您在调试器,检查器或其他工具中查看对象,您将看到符号名称而不是1,2或3(或者您通常使用的任何值)。

这是Lisp风格的一部分:尽可能使用符号名称。仅在外部函数的接口代码中使用带数值的符号(例如调用使用枚举的外部C代码)。

答案 2 :(得分:6)

枚举对Lisp来说是多余的,原因是所有符号都是他们自己的身份,所以你可以使用它们,例如:

[dsm@localhost:~]$ clisp -q
[1]> (setf x 'some) ;'
SOME
[2]> (eq x 'some) ;'
T
[3]>