在大多数实现中,无论是否为该类型定义构造函数,都可以使用(make-instance 'struct-type)
创建结构。这不适用于Allegro或ABCL,但这些实现仍然可以在#S(struct-type)
的读取时创建结构,这使我认为必须有其他方法在运行时构造它们,因为类型名称为一个符号。
答案 0 :(得分:1)
您不应混合结构和对象创建。标准为standard-class
和symbol
定义make-instance
,以便将提供的符号传递给find-class
,然后make-instance
递归。
因此,对于命名结构类型扩展make-instance
的库存实现不符合要求,如果您依赖它,则代码也不符合。
然后,#S
is specified只有在结构具有标准构造函数时才能正常工作,因此没有多少魔法。
鉴于此限制,您可以通过实现与结构名称连接的名为#S
的符号,然后是关键字参数列表来实现make-
。
但同样,依赖于实现的细节会受到影响。您询问何时没有构造函数,这意味着:constructor nil
中的defstruct
。请注意,不指定构造函数参数意味着它将具有默认构造函数。该实现可以具有内部簿记,包括它创建的隐藏标准构造函数,而不管您在make-load-form-using-slots
中使用的选项(或无参数构造函数和插槽访问器),扩展#S
,并可能优化通过make-load-form
对结构的专门化,在文件编译中加载文字结构(而不是创建一个的形式)。
答案 1 :(得分:0)
也许不是很优雅,但是关于:
(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)
答案 2 :(得分:0)
我想过一个可能的解决方案,但这有点像黑客攻击。由于#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-
前缀的名称,也应该调用默认构造函数。