(make-instance 'struct-type)
在大多数实现中,无论您是否为该类型定义了构造函数,都可以使用它来创建结构。这在 Allegro 或 ABCL 上不起作用,但这些实现仍然可以在读取时创建结构体#S(struct-type)
,这让我认为在将类型名称作为符号的情况下必须有其他方法在运行时构造它们。
3 回答
你不应该混合结构和对象创建。make-instance
为standard-class
和 for定义的标准,symbol
以便将提供的符号传递给find-class
,然后make-instance
递归。
因此,make-instance
为命名结构类型扩展的库存实现不符合要求,如果您依赖它,您的代码也不是。
然后,#S
指定仅当结构具有标准构造函数时才能正常工作,因此那里没有太多魔力。
鉴于此限制,您可以#S
通过将名为 concatenated 的符号make-
与结构名称连接起来,然后是关键字参数列表来实现自己。
但同样,实现相关的细节也受到了影响。您询问何时没有构造函数,这意味着:constructor nil
在defstruct
. 请注意,不指定构造函数参数意味着它将具有默认构造函数。该实现可以具有内部簿记,包括它创建的隐藏标准构造函数,无论您要在 中使用的选项(或无参数构造函数和插槽访问器)如何make-load-form-using-slots
,扩展#S
,并可能优化文字结构加载(与创建一)通过make-load-form
对结构的专门化在文件编译中。
也许不是很优雅,但是关于:
(defun make-struct-by-name (name &rest args)
(apply (symbol-function
(intern (concatenate 'string "MAKE-"
(symbol-name name))))
args))
用法:
CL-USER> (defstruct foo
a b)
FOO
CL-USER> (make-struct-by-name 'foo :a 1 :b 2)
#S(FOO :A 1 :B 2)
我已经想到了一个潜在的解决方案,但这有点像黑客。由于#S
阅读器宏可以工作,但我不知道 ABCL 和 Allegro 是如何实现它的(它可能完全在实现内部,而不是在 Lisp 中定义),我至少可以生成一个字符串并以编程方式在其上调用阅读器宏函数:
(defun make-struct-from-type (type-name)
(with-input-from-string
(s (format nil "(~A::~A)"
(package-name (symbol-package type-name))
(symbol-name type-name)))
(funcall (get-dispatch-macro-character #\# #\S)
s #\S nil)))
不过,这可能不适用于其他实现。SBCL 抱怨sb-impl::*read-buffer*
未绑定,因此可能需要更多技巧来欺骗实现,使其认为阅读器宏是在典型上下文中调用的。
即使给定一个没有默认make-
前缀的名称,这也应该调用默认构造函数。