右侧也被分配

时间:2019-04-23 20:56:41

标签: list common-lisp variable-assignment

直接说明问题;我在let语句中将'temp'分配为* TEMP *。当我这样做时,将为* TEMP *精确分配每次迭代中已分配的'temp'。最后,我最终将'temp'的值推后。不知道为什么,你们对这里的错误情况有任何想法吗?

(defparameter *TEMP* `((key value)(key2 value2)(key3 x))
(defparameter *SYNS* NIL)
(defparameter *PUSH-HERE* NIL)

(dolist (i *matrix*)
  (dolist (j i)
    (if  (equal 'keyword (first j)) 
        (foo (second j))))       ;fills *SYNS*
  (let ((temp *TEMP*))
    ;(print *TEMP*) prints temps last assigned value?
    (set-key temp (get-key i))   ;gets key's value
    (set-key2 temp (get-key2 i)) ;gets key2's value    
    (loop while (not (equal 0 (length *SYNS*)))
          do (set-key3 temp (pop *syns*))
          (push temp *PUSH-HERE*))))

结果值变成这样;

 ((key last-assigned-value)(key2 last-assigned-value)(key3 last-assigned-value)
 (key last-assigned-value)(key2 last-assigned-value)(key3 last-assigned-value)
 (key last-assigned-value)(key2 last-assigned-value)(key3 last-assigned-value))

代替;

((key first-assigned-value)(key2 first-assigned-value)(key3 first-assigned-value)
 (key second-assigned-value)(key2 second-assigned-value)(key3 second-assigned-value)
 (key last-assigned-value)(key2 last-assigned-value)(key3 last-assigned-value))

我尝试打印,并且在推行之前,可以根据需要打印temp,但是在整个迭代完成之后,我得到了上面放的无意清单。

3 个答案:

答案 0 :(得分:2)

您正在将*temp*的地址绑定到temp。我假设set-keytemprplaca一样更新(setf (car place) value)。因此,您也在修改*temp*,因为它的值与temp相同。每一轮您都要覆盖 temp ,这是您一直推送到新列表的相同地址,因此由于相同,因此会导致3个子列表相同。这也违反了Common Lisp,因为*temp*被引用为文字数据,因此是常量数据。在不同的实现中,它的行为可能有所不同。

代替破坏性操作,您可以执行创建新值的非破坏性操作,例如。 substitute-if,然后更新绑定:

(setf temp 
      (substitute-if (cons 'key 'new-value) 
                     (lambda (e) (eq e 'key)) 
                     temp
                     :key #'car))

如果您仍然想要突变,可以使用copy-alist来摆脱它:

(let ((temp (copy-alist *temp*)))
  ...)

答案 1 :(得分:2)

变量是一个包含值的框。缺点单元格(例如,您放入*temp*中的列表的开头)是内存中带有一些指针的位置。当您执行(let ((temp *temp*)) ...时,您使变量temp指向与*temp*相同的内存位,因此,当您修改该数据结构时,您将修改指向的相同内存。到*temp*

修复代码的一种方法是尝试查看通常如何编写Lisp程序并使代码更像这样,而不是运用您的知识如何将C程序编写为具有非常不同的语义的语言(特别是, Common Lisp没有像C)这样的值语义。一种改进是构造所需的数据,而不是用筷子(即set-key和朋友)戳它。 我无法执行您的代码,因为您未能提供一个最低限度的可执行示例,但是您可以通过执行以下操作从所需的输出构造一行:

`((key ,what-you-want-for-first-value)
  (key2 ,second-value)
  (key3 ,third))

这将在新的内存中创建一个新对象。

答案 2 :(得分:1)

  

我在let语句中将'temp'分配为* TEMP *。当我这样做时,* TEMP *会被精确分配每次迭代中已分配的“温度”

变量/** * Computes a unique slug for the post, when given the desired slug and some post details. * * @since 2.8.0 * * @global wpdb $wpdb WordPress database abstraction object. * @global WP_Rewrite $wp_rewrite * * @param string $slug The desired slug (post_name). * @param int $post_ID Post ID. * @param string $post_status No uniqueness checks are made if the post is still draft or pending. * @param string $post_type Post type. * @param int $post_parent Post parent ID. * @return string Unique slug for the post, based on $post_name (with a -1, -2, etc. suffix) */ function wp_unique_post_slug( $slug, $post_ID, $post_status, $post_type, $post_parent ){} 与变量temp的值相同。如果是列表,则完全相同的对象。 *temp*未获得新值。

*temp*