对引用类型赋值感到困惑

Confused about the reference type assignment

以下是链表实现的一部分,我对语义感到困惑:

class Node<T> {
    var value: T
    var next: Node?
    weak var previous: Node?
    
    init(value: T) {
        self.value = value
    }
}

struct LinkedList<T> {
    var head: Node<T>?
    var tail: Node<T>?
    
    init() { }
    
    // what this method actually does is unimportant, but it creates a linked list from a sequence
    func createChain<S>(of sequence: S) -> (head: Node<T>, tail: Node<T>)? where S: Sequence, S.Element == T {
        var iterator = sequence.makeIterator()
        guard let firstValue = iterator.next() else {
            return nil
        }
        var head: Node<T>
        var tail: Node<T>
        
        var currentNode = Node(value: firstValue)
        head = currentNode
        
        while let nextValue = iterator.next() {
            let newNode = Node(value: nextValue)
            currentNode.next = newNode
            newNode.previous = currentNode
            currentNode = newNode // ?
        }
        
        tail = currentNode
        return (head: head, tail: tail)
    }
}

假设我要使用上面的代码创建一个链表:

let linkedList = LinkedList<Int>()
let sequence = [0, 1, 2]
let chain = linkedList.createChain(of: sequence)

while 循环的第一个循环中,快照如下:

while let nextValue = iterator.next() {
    let newNode = Node(value: nextValue) // newNode: previous = nil, next = nil, value = 1
    currentNode.next = newNode // currentNode: previous = nil, next = newNode, value = 0
    newNode.previous = currentNode // newNode: previous = currentNode, next = nil, value = 1
    currentNode = newNode // ?
}

当最后一行执行时,我表面上理解新节点必须不断替换当前节点以循环遍历序列的所有元素,但我不确定 [=14= 时发生了什么] 设置 newNodenewNode 覆盖 currentNode 没有意义,因为 currentNodenext 刚刚分配给 newNodenewNodenext 为零。

如果newNode不覆盖currentNodenewNode的内容如何不影响currentNode = newNode中的currentNode

类 是 引用类型 。这意味着 currentNode 持有对 Node 实例的引用。当您将新实例分配给 currentNode 时,您正在更改引用的对象。只要某个其他变量或 属性 持有对前一个实例的引用,它就会保留在内存中。

这就是为什么将第一个 Node 称为 currentNode 分配给 head 很重要;如果 head 没有持有引用,那么当一个新的 Node 被分配给 currentNode 时,Node 将被释放。对后续 Node 的引用由 previousnext 属性保存,并将它们也保存在内存中。

为了说明,我将使用 *0、*1 等表示的虚构内存地址来显示序列:

while 循环之前:

  • currentNode = Node*0(0,nil,nil)
  • head = Node*0(0,nil,nil)

注意currentNodehead指的是相同的内存地址。

第一次通过 while 循环:

  • currentNode = Node*0(0,nil,nil)
  • newNode = Node*1(1,nil,nil)
  • currentNode = Node*0(0,Node*1,nil)
  • newNode = Node*1(0,nil,Node*0)
  • currentNode = Node*1(nil,Node*0)

请注意 currentNode 现在引用 Node*1head 仍然引用 Node*0 以及 Node*1

previous

下一次通过 while 循环:

  • currentNode = Node*1(1,nil,Node*0)
  • newNode = Node*2(2,nil,nil)
  • currentNode = Node*1(0,Node*2,nil)
  • newNode = Node*2(0,nil,Node*1)
  • currentNode = Node*2(nil,Node*1)

以此类推

最后,createChain的实现有点奇怪;它 returns 一个 (head,tail) 的元组,它在一个空的 LinkedList.

上运行

你可以将它实现为一个静态函数 returns a LinkedList -

struct LinkedList<T> {
    var head: Node<T>
    var tail: Node<T>
    
    // what this method actually does is unimportant, but it creates a linked list from a sequence
    static func createChain<S>(of sequence: S) -> LinkedList<S.Element>? where S: Sequence, S.Element == T {
        var iterator = sequence.makeIterator()
        guard let firstValue = iterator.next() else {
            return nil
        }
        var head: Node<S.Element>
        var tail: Node<S.Element>
        
        var currentNode = Node(value: firstValue)
        head = currentNode
        
        while let nextValue = iterator.next() {
            let newNode = Node(value: nextValue)
            currentNode.next = newNode
            newNode.previous = currentNode
            currentNode = newNode // ?
        }
        
        tail = currentNode
        return LinkedList(head: head, tail: tail)
    }
}

然后你可以用

创建你的链表
let sequence = [0, 1, 2]

let list = LinkedList.createChain(of: sequence)