【问题标题】:Recursive class initialisation in SwiftSwift 中的递归类初始化
【发布时间】:2017-11-21 08:32:37
【问题描述】:

我正在构建一个简单的树数据结构,它接受一些输入并在树中创建节点,直到输入足够小。这一切都很好(而且非常简单)。出于遍历的原因,我想在每个节点上包含对父节点的引用(这样我可以将它“向上”走回),或者在 root 的情况下为 nil。我尝试或多或少地这样做(当然,这是一个更简单的版本——实际的树是一个八叉树):

class Recursive {
    let value: Int
    let child: Recursive?
    weak var parent: Recursive?

    init(value: Int, parent: Recursive? = nil) {
        self.value = value
        self.parent = parent

        if value > 1 {
            self.child = Recursive(value: value-1, parent: self) // fails
        } else {
            self.child = nil
        }
    }
}

var r: Recursive? = Recursive(5)

while r != nil {
    print(r!.value)
    r = r!.child
} // should print 5, 4, 3, 2, 1

当然,这实际上是行不通的。似乎您不能在 init 方法中将“self”作为参数传递。我想这是因为整个两步初始化的事情。在 Swift 中处理这类事情的最佳(最惯用和/或最方便和/或最高效)的方法是什么?我之前主要写过 Python 和一点 C,所以这些 Swift 的东西对我来说都是全新的。

我想我可以编写一个单独的函数来初始化树,但似乎应该可以通过初始化方法来完成这一切。我只是不知道怎么做。

【问题讨论】:

    标签: swift


    【解决方案1】:

    问题是您只能将self 传递给递归调用 在它被完全初始化之后(否则递归调用 函数可以访问未初始化的属性)。

    一个可能的解决方案是在之后分配孩子的父母 child 已构建。这使您可以将child 保持为常数 属性:

    class Recursive {
        let value: Int
        let child: Recursive?
        weak var parent: Recursive?
    
        init(value: Int) {
            self.value = value
            if value > 1 {
                self.child = Recursive(value: value - 1)
                // Now `self` is fully initialized!
                self.child?.parent = self
            } else {
                self.child = nil
            }
        }
    }
    

    只是为了好玩:“链表遍历”可以不用 强制解包:

    var r: Recursive? = Recursive(value: 5)
    while let node = r {
        print(node.value)
        r = node.child
    }
    

    甚至更短,带有一个常量列表头:

    let r = Recursive(value: 5)
    for node in sequence(first: r, next: { $0.child }) {
        print(node.value)
    }
    

    【讨论】:

    • 好的,有道理。感谢您关于使用序列的建议。真的很方便。
    【解决方案2】:

    您的child 参数应该是var 而不是let,它应该可以工作。您还可以删除else,因为child 默认为nilvar 默认为nil

    【讨论】:

    • 确实有效。但为什么?我不太了解 Swift 的类实例初始化。为什么我可以递归地分配变量而不是常量?关于孩子的默认值的好点。
    • 因为默认情况下let 选项未使用nil 进行初始化,并且您在初始化之前尝试访问您的实例。
    猜你喜欢
    • 1970-01-01
    • 2021-01-17
    • 1970-01-01
    • 2019-10-04
    • 2017-12-21
    • 1970-01-01
    • 1970-01-01
    • 2017-05-10
    • 2016-10-20
    相关资源
    最近更新 更多