考虑一下:
(defclass my-string ()
((data :initarg :data :type simple-string)
(properties :initarg :properties :type interval-tree))
(:documentation
"Represents a string with properties."))
我想在 typecase 表达式中使用 my-string 作为类型:
(defun upcase (obj)
(typecase obj
(my-string (string-upcase (slot-value obj 'data)))
(string (string-upcase obj))
(integer (char-upcase (code-char obj)))
(character (char-upcase obj))
(otherwise (error "Wrong type argument ~S" obj))))
我以为类是类型,但显然不是,因为上面的代码是编译器错误。所以我声明了一个类型:
(deftype my-string (s) (typep s 'my-string))
看来我必须像这样使用它(否则我会收到编译错误,typedef 需要一个参数):
(defun upcase (obj)
(typecase obj
((my-string obj) (string-upcase (slot-value obj 'data)))
(string (string-upcase obj))
(integer (char-upcase (code-char obj)))
(character (char-upcase obj))
(otherwise (error "Wrong type argument ~S" obj))))
但是 SBCL 删除了我的代码,因为无法访问!:-)
我该怎么做?如何正确声明类的类型,以便可以在类型声明可用的表达式中使用它?
我知道我可以使用结构而不是类,在这种情况下,编译器会为该类型生成代码,并且初始类型“正常工作”:
(defstruct my-string
data properties)
宏扩展和查看生成的代码并没有真正让我更加明白。我看到的是:
(SB-C:XDEFUN MY-STRING-P
:PREDICATE
NIL
(SB-KERNEL::OBJECT)
(TYPEP SB-KERNEL::OBJECT 'MY-STRING))
它确实做了我所做的事,但我认为该函数不参与其中,还是我错了?要么他们以某种方式在内部将结构与类型关联起来,要么我错过了生成代码的一些相关部分?我对这些都不是很熟悉,所以也很有可能。
一个相关的问题:在 CommonLisp 中,对扩展内置类型(如字符串)的自定义类进行建模的正确方法是什么?像在 my-string 中所做的那样,进行组合是一种更好的方法吗?还是从某个内置的 CL 字符串类继承更好?基于这个 SX 问题和答案,在我看来,继承并不是对类型进行建模的最佳方式,这可能是更好的,因为我们不喜欢 Java 或旧 C++ 中的分类法。
最后,在这种情况下,我甚至不需要 typecase,如果我将 upcase 变成一个专门针对这些类型的通用方法,整个问题就消失了,我完全知道这一点。但是,我想更多地了解类型和类,以及如何在 CL 中对类似上述内容进行建模。
抱歉,这篇文章有点长,而且一个问题太多了,我才刚刚开始学习。感觉我遇到的每一个问题和寻找答案的尝试都会引出另外 10 个问题 :)。