在大多数实现中,无论是否为该类型定义了构造函数,都可以使用(make-instance 'struct-type)创建结构。这在Allegro或ABCL上不起作用,但这些实现仍然可以使用#S(struct-type)在读取时创建结构,这让我认为一定有其他方法在运行时构造它们,给定类型名作为符号。
发布于 2015-05-05 02:21:36
你不应该把结构和对象创建混为一谈。标准为standard-class和symbol定义了make-instance,以便将提供的符号传递给find-class,然后make-instance递归。
因此,为命名结构类型扩展make-instance的常规实现是不一致的,如果您依赖它,那么您的代码也是不一致的。
然后,只有当结构有一个标准的构造函数时,#S is specified才能正确工作,所以没有留下太多的魔力。
考虑到这一限制,您可以通过嵌入一个名为make-的符号来实现#S,该符号与结构名称连接在一起,后跟关键字参数列表。
但又一次,依赖于实现的细节命中。你会问到什么时候没有构造函数,这意味着defstruct中的:constructor nil。请注意,不指定构造函数参数意味着它将具有默认构造函数。实现可以有内部记账,包括一个隐藏的标准构造函数,它创建一个隐藏的标准构造函数(或无参数构造函数和槽访问器)以在make-load-form-using-slots中使用,一个扩展的#S,并可能通过make-load-form对结构的专门化在文件编译中优化文本结构加载(与创建文本结构的表单相反)。
发布于 2015-05-05 02:43:08
也许不是很优雅,但有什么关系:
(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)发布于 2015-05-05 08:06:14
我已经想出了一个潜在的解决方案,但它有点像黑客。由于#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-前缀。
https://stackoverflow.com/questions/30030304
复制相似问题