不变性和循环引用

时间:2017-11-27 15:32:13

标签: oop functional-programming immutability circular-reference

我将使用python作为示例代码,但我确信这个问题可以在大多数编程语言中重现。

假设我有一个班级:

class Node(object):

    def __init__(self, value=None, prev=None, next=None):
        self._value = value
        self._prev = prev
        self._next = next

    def with_value(self, value):
        return Node(value=value, prev=self._prev, next=self._next)

    def with_prev(self, prev):
        return Node(value=self._value, prev=prev, next=self._next)

    def with_next(self, next):
        return Node(value=self._value, prev=self._prev, next=next)

所以基本上,这允许我们创建一个Node实例,如下所示:

node = Node()
      .with_value(30)
      .with_prev(
         Node()
         .with_value(25))
      .with_next(
         Node()
         .with_value(35))

此处的问题是每个Node都需要引用上一个和下一个节点,因此实际上我们需要修复这些with_prevwith_next方法:

def with_prev(self, prev):
    prev = prev.with_next(self)
    return Node(value=self._value, prev=prev, next=self._next)

但这不对...... 上一个节点现在对已被丢弃的实例有next引用。

如果我试图这样做,我有类似的问题:

def with_prev(self, prev):
    node = Node(value=self._value, prev=prev, next=self._next)
    prev = prev.with_next(node)
    return node

我的node实例现在有一个不正确/过时的prev引用。

我该如何解决这个问题?

1 个答案:

答案 0 :(得分:0)

您可以通过将nextprev引用更改为懒惰评估为实际引用的thunk来实现。但是,要想做到这一点很棘手,并且需要立即初始化整个列表。

更简单的方法是只存储单链表,然后使用zipper在遍历时跟踪反向链接。如果你需要能够从列表的尾部开始遍历,只需存储两个列表,一个带有前向链接,另一个带有后面。