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

use*_*854 3 lisp arrays 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))))
Run Code Online (Sandbox Code Playgroud)

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

然而,

(setq searcher (read))
(setf (schedule-day (aref october (- searcher 1))) searcher)
Run Code Online (Sandbox Code Playgroud)

我在这方面遇到麻烦.如果我输入17,那么只有第17天会october受到影响并打印出来,

-month:10 day:0
-month:10 day:0
...
-month:10 day:17
-month:10 day:0    
...
Run Code Online (Sandbox Code Playgroud)

但我真正得到的是

-month:10 day:17
-month:10 day:17
-month:10 day:17
...
Run Code Online (Sandbox Code Playgroud)

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

october[searcher - 1].setDay(searcher);
Run Code Online (Sandbox Code Playgroud)

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

sds*_*sds 6

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

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

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

(apply #'vector (loop repeat 31 collect (make-instance 'schedule)))
Run Code Online (Sandbox Code Playgroud)

要么

(make-array 31 :initial-contents (loop repeat 31 collect (make-instance 'schedule)))
Run Code Online (Sandbox Code Playgroud)

您混淆的根本原因是您指定了数组元素类型并假设您创建了一个"专用"数组.因此,尽管您实际上(make-instance 'schedule)只调用一次,但在连续的内存中将有31个对象.但是,您的实现没有义务以这种方式遵守元素类型规范(它将创建一个可以保存您指定类型的对象的数组,但不一定 只包含那些对象),而您实际获得的是a simple-vector.

PS.你应该使用defvardefparameter 代替setqsetf定义全局变量(比如october),你应该使用"耳罩"来命名它们 ,比如*october*.