无法修改对象数组中的特定元素

时间:2016-09-26 12:21:06

标签: arrays lisp common-lisp

(defclass schedule ()
   ((day :accessor schedule-day :initarg :day)))
(setf october 
   (make-array '(31) 
      :element-type 'schedule 
      :initial-element 
         (make-instance 'schedule :day 0)))
(setq searcher (read))
(setf (schedule-day (aref october (- searcher 1))) searcher)

(dotimes (i 31)
  (format t "-month:10 day:~S~%" (schedule-day (aref october i))))

这是我的十月调度计划的一部分。 这部分应该是我输入的那一天,并更改当天的元素,并打印每个十月的时间表。

然而,

(setq searcher (read))
(setf (schedule-day (aref october (- searcher 1))) searcher)

我遇到了麻烦。如果我输入17,那么只有october的第17天会受到影响并打印出来,

-month:10 day:0
-month:10 day:0
...
-month:10 day:17
-month:10 day:0    
...

但我真正得到的是

-month:10 day:17
-month:10 day:17
-month:10 day:17
...

为什么我不能只改变一个元素?我设法用c ++这样做,

october[searcher - 1].setDay(searcher);

似乎setf影响类本身,而不影响类对象。你能帮助我吗?谢谢。

2 个答案:

答案 0 :(得分:6)

您的问题是您的数组包含31个指针,每个指针指向同一个对象。

因此(setf (schedule-day (aref october a)) b)修改了该唯一对象。

您可以通过封装october来实现所需的目的,以便仅在必要时创建i元素,或者通过使用类似

的内容初始化数组来实现
(apply #'vector (loop repeat 31 collect (make-instance 'schedule)))

(make-array 31 :initial-contents (loop repeat 31 collect (make-instance 'schedule)))

您混淆的根本原因是您指定了数组元素类型并假设您创建了"specialized" array。 因此,尽管您实际上只调用(make-instance 'schedule)一次,但在连续内存中将有31个对象。 但是,您的实施有义务兑现 方式的元素类型规范(它将创建一个数组 可以保存您指定类型的对象,但不一定 那些对象), 你实际得到的是simple-vector

PS。你应该 使用defvar or defparameter 而不是setqsetf来定义全局 变量(如october),你应该命名它们 运用 "earmuffs", 比如*october*

答案 1 :(得分:4)

您可以很容易地看到数组元素只指向一个CLOS对象。

CL-USER 28 > (defclass foo () ())
#<STANDARD-CLASS FOO 4020002613>

CL-USER 29 > (make-array 3 :initial-element (make-instance 'foo))
#(#<FOO 402000AE9B> #<FOO 402000AE9B> #<FOO 402000AE9B>)

所有对象都具有相同的ID 402000AE9B

在下一个示例中,对象是不同的:

CL-USER 30 > (make-array 3 :initial-contents (list (make-instance 'foo)
                                                   (make-instance 'foo)
                                                   (make-instance 'foo)))
#(#<FOO 4020000B43> #<FOO 4020000B63> #<FOO 4020000B83>)

所有ID都不同。