分配是一个操作人员在命令编程语言,如C类或Java语言.
分配是一个数据移动操作员。也就是说,它从一个变量到另一个。例如,假设我们有两个变量A和B,值分别为1和2。即:
---------+-------变量|值---------+-------答|1---------+-------B|2(B | 2)---------+-------
赋值语句“A:=B”(*)将具有以下效果:
---------+-------变量|值---------+-------A|2类---------+-------B|2(B | 2)---------+-------
如您所见,A现在的值与B之前的值相同,而B保留其旧值。也就是说,A收到复制B值的一半。
分配之所以无处不在,部分是因为它直接映射到如何使机器将数据从一个存储单元传输到另一个存储元。然而,此复制语义学显示了存储在变量中的数据不仅仅是简单数据时的一些问题数据类型.
例如,如果A和B很大矩阵赋值语句必须逐个元素复制整个矩阵,而不是简单的整数。这显然是低效的。这个问题的解决方案通常是使用赋值来复制指针或参考文献相反。现在,我们不需要复制整个矩阵,只需要复制指向矩阵所在内存位置的指针。
然而,效率的提高带来了另一个问题:混叠。使用引用符号,语句A:=B将使A和B引用相同的数据。因此,当A所指的数据发生变化时,B也会发生变化。这可能会导致意外问题。
例如,A和B是链表,我们调用一个过程append(A,B),将列表B附加到列表A的末尾。当A和B引用同一个列表时会发生什么?
解决这些问题的方法有很多。一种方法是在复制值时要注意效率,在复制引用时要注意推理。
另一个选择是完全取消分配!一些逻辑和函数语言可以做到这一点,比如哈斯克尔。其他,比如Lisp语言有赋值,但通常不鼓励使用。
处理这个问题的一种新方法是用交换,因此在我们的原始示例中,交换操作的效果将是:
---------+-------变量|值---------+-------A|2类---------+-------B|1(B |1)---------+-------
由于交换交换了A和B的值,因此对于大型数据结构(内部实现为交换引用,而不是复制每个值)来说,这可能是高效的。而且,由于交换不会使两个变量引用相同的值,因此它不会有别名问题。
(*)C和Java使用符号“=作为赋值运算符,但我选择使用:=“因为前者可能被误认为是等式运算符。
参考和进一步阅读:
Bruce W.Weide、Scott M.Pike和Wayne D.Heym,为什么要交换?,《RESOLVE 2002年研讨会会议记录》,在线版本,网址:http://people.cs.vt.edu/~edwards/RESOLVE2002/程序/Wide2.html