swift - 协议(protocol)符合Sequence协议(protocol),同时消除通用约束问题

标签 swift generics tree protocols sequence

尝试创建一个用于在树中创建不同节点的协议(protocol)。简化版本是:

protocol NodeElement {
    var children: [NodeElement] { get }
}

此协议(protocol)可用于创建可用于在树中创建节点的结构。

struct TextNode: NodeElement {
    var text: String
    var children: [NodeElement]
}

struct NumberNode: NodeElement {
    var number: Int
    var children: [NodeElement]
}

使用这些结构,可以创建包含不同类型的树。

let root = TextNode(text: "Hello", Children: [NumberNode(...), ...])

我希望 NodeElement 符合序列协议(protocol),以允许在 for...in 循环内进行前序树遍历。

这可以通过

来完成
protocol NodeElement: Sequence { ... }

extension NodeElement {
    func makeIterator() -> AnyIterator<NodeElement> {
        var stack: [NodeElement] = [self]

        return AnyIterator {
            if let next = stack.first {
                stack.remove(at: 0)
                stack.insert(contentsOf: next.content, at: 0)
                return next
            }
            return nil
        }
    }
}

如果这样做,则会出现以下错误:

error: protocol 'NodeElement' can only be used as a generic constraint
because it has Self or associated type requirements

var content: [NodeElement] { get }
              ^

即使我相信我完全遵守序列协议(protocol),也会发生这种情况。

如果不将 NodeElement 创建为 struct 并让所有节点都继承它,有什么方法可以实现此功能吗?

最佳答案

NodeElement 有对其自身的引用,因此不能用于定义具体类型。因此,您将无法将其设为序列。

但是,您可以通过简单地将计算变量添加到协议(protocol)而不是使其本身成为序列来实现类似的效果。

例如:

extension NodeElement 
{
    var treeNodes : AnyIterator<NodeElement>  
    {
        var stack: [NodeElement] = [self]

        return AnyIterator {
            if let next = stack.first {
                stack.remove(at: 0)
                stack.insert(contentsOf: next.children, at: 0)
                return next
            }
            return nil
        }
    }
}

然后,您将能够使用该变量在 for ... in 循环中使用您的协议(protocol):

for node in root.treeNodes
{
   ...
}

关于swift - 协议(protocol)符合Sequence协议(protocol),同时消除通用约束问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43144738/

相关文章:

swift - CABasicAnimation swift 不工作

ios - 如何使用 UIStackView 更改 UITableViewCell 的布局

ios - 如何将实例方法作为闭包参数传​​递给另一个函数?

swift - 如何将集合的 Swift 扩展限制为泛型类型?

java - TreeCellRenderer 的设计

javascript - 如何在javascript中从数组制作二叉树?

ios - 应用程序快捷方式打开 TableView 行

c# - 泛型异常

java - 帮助我使用通用数据类型

java - 二叉搜索树是平衡的吗?