How to use `setcdr` with buffer-local variables

2019-03-02 22:29发布

问题:

I am experiencing behavior using setcdr that would seem to suggest that it is not confined to buffer-local variables containing the same name in different buffers. I have tried using with-current-buffer, but that does not correct the issue.

For example, buffer-A and buffer-B both contain a local-variable named variable-one, which is a cons cell -- e.g., (overlay-string t), and setcdr is being used to set the cdr value to either t or nil.

Is there a way to ensure that setcdr remains confined to modifying only the buffer-local value?

回答1:

No, there is no buffer-local value for the cdr of the list.

If two variables point at the same list, and you modify the list, then you will see the effect in both the variables.

That has nothing to do with buffer-local variables, and everything to do with what it means to assign a list to a variable.

If you want the two variables to point to different lists, then you need to copy the entire list.

You can use (copy-sequence LIST) to copy a list. Or (append LIST nil) is also common (as append copies all except the final argument).

n.b. Those functions create a new list structure, but the values in the list are still the original objects. Typically that's all that's required, but if you do need the list contents to be entirely independent of one another, then use copy-tree instead.



回答2:

I don't think you can, as with setcdr you are modifying the value bound to the variable you declared buffer-local. If you didn't assign a new value to the buffer-local variable, that value is its default value. Note that what is buffer local is the binding of the variable name to its value.

The only way (that I know) would be to assign a copy to your buffer-local variable and then use setcdr. This needs to be done in every buffer.

An alternative is to not use setcdr at all, and use setq instead:

(setcdr foo bar) ===> (setq foo (cons (car foo) bar))



标签: emacs elisp