【问题标题】:Swift 4 GenericsSwift 4 泛型
【发布时间】:2018-04-22 14:23:27
【问题描述】:

我正在尝试学习 Swift 4 泛型并编写了一些无法编译的代码。我不明白为什么。代码如下:

protocol NodeType {
    associatedtype T
    associatedtype E
    var parent: T {get set}
    var children: [T] {get set}
    var item: E {get set}
    func getItem()->E
    mutating func setItem(_ newItem: E)
    func getParent()->T
    mutating func setParent(_ theParent:T)
    func getChild(at index:Int)->T
    mutating func insertChild(at index:Int, child: T)
    func find(_ node:T)->Int
}

protocol ItemType:Equatable {
    associatedtype E
    var payload: E {get set}
    func matches(_ item:E)->Bool
}

struct Item<E:Equatable>: ItemType {
    var payload: E
    func matches(_ item: E) -> Bool {
        return payload == item
    }
}

struct Node<T:NodeType, E:ItemType>: NodeType {
    var parent: T
    var children: [T]
    var item: E

    func getItem()->E {
        return item
    }

    func find(_ node: T) -> Int {
        for aNode in children {
            // ********************************************************************
            // the following line fails: Value of type 'T.E' has no member 'matches'
            if aNode.getItem().matches(node) {
            }
        }
    }

    mutating func setItem(_ newItem: E) {
        item = newItem
    }

    func getParent()->T {
        return parent
    }

    mutating func setParent(_ theParent:T) {
        parent = theParent
    }

    func getChild(at index:Int)->T {
        precondition(0..<children.count ~= index)
        return children[index]
    }

    mutating func insertChild(at index:Int, child: T) {
        precondition(0...children.count ~= index)
        if index == children.count {
            // append at end
            children.insert(child, at: children.endIndex)
        }
        else {
            children.insert(child, at: index)
        }
    }
}

我的理解是,aNode 的类型 T 被限制为 NodeType,而 aNode.getItem() 是类型 E,被限制为 ItemType,其中包含函数匹配项。谁能告诉我哪里出错了。

【问题讨论】:

    标签: xcode generics swift4 swift-protocols


    【解决方案1】:

    我认为问题在于您一直使用占位符名称TE 让自己感到困惑。此声明中的E

    struct Node<T:NodeType, E:ItemType>
    

    ...不是此声明中的E

    protocol NodeType {
        associatedtype T
        associatedtype E
    

    没有理由相信 NodeType 的 E 是 ItemType 采用者,或者它是 Equatable。

    如果您在不同的泛型中为占位符选择不同的名称,这对您来说会更加明显(您可以使用 Xcode 的重构功能来帮助您)。例如:

    protocol NodeType {
        associatedtype NodeTypeParent
        associatedtype NodeTypeItem
        // ...
    }
    protocol ItemType:Equatable {
        associatedtype ItemTypePayload
        // ...
    }
    struct Item<ItemPayload:Equatable>: ItemType {
        // ...
    }
    struct Node<NodeParent:NodeType, NodeItem:ItemType>: NodeType {
        // ...
    }
    

    现在你会收到消息

    “NodeParent.NodeTypeItem”类型的值没有成员“匹配”

    我认为这更清晰。

    【讨论】:

    • 对于协议中的每个associatedtype 声明,以及结构声明中尖括号中声明的每个占位符,使用不同的占位符名称。这样你就不会这样迷惑自己了。
    • 谢谢,有用的建议
    • 等一下,我用完全不同的名字改写了,我会发布来澄清一下。
    • 谢谢,明天有机会看看你的答案时我会的。
    【解决方案2】:

    看了 Matt 的回答后,我意识到 NodeType 的基本结构是错误的,部分原因是我混淆了通用占位符。下面的代码现在可以编译了。

    fileprivate let NotFound = -1
    
    protocol NodeType {
        associatedtype Node
        associatedtype Element:Equatable
        var parent: Node? {get set}
        var children: [Node] {get set}
        var item: Element {get set}
        func isRoot()->Bool
        func getItem()->Element
        mutating func setItem(_ newItem: Element)
        func getParent()->Node?
        mutating func setParent(_ theParent:Node)
        func getChild(at index:Int)->Node
        mutating func insertChild(at index:Int, child: Node)
        func matches(_ node:Node)->Bool
        func find(_ node:Node)->Int
    }
    
    class TreeNode<ThisNodeElement:Equatable>: NodeType {
        var parent: TreeNode?
        var children: [TreeNode]
        var item: ThisNodeElement
    
        init(withNode node:TreeNode, value:ThisNodeElement) {
            parent = node
            item = value
            children = []
        }
    
        init(root value:ThisNodeElement) {
            parent = nil
            item = value
            children = []
        }
    
        func isRoot() -> Bool {
            return parent == nil
        }
    
        func getItem()->ThisNodeElement {
            return item
        }
    
        func setItem(_ newItem: ThisNodeElement) {
            item = newItem
        }
    
        func getParent()->TreeNode? {
            return parent
        }
    
        func setParent(_ theParent:TreeNode) {
            parent = theParent
        }
    
        func getChild(at index:Int)->TreeNode {
            precondition(0..<children.count ~= index)
            return children[index]
        }
    
        func insertChild(at index:Int, child: TreeNode) {
            precondition(0...children.count ~= index)
            if index == children.count {
                // append at end
                children.insert(child, at: children.endIndex)
            }
            else {
                children.insert(child, at: index)
            }
        }
    
        func matches(_ node:TreeNode)->Bool {
            return node.item == item
        }
    
        func find(_ node: TreeNode) -> Int {
            let index = children.index { (thisNode:TreeNode) -> Bool in
                return node.matches(thisNode)
            }
            return index ?? NotFound
        }
    }
    

    【讨论】:

    • 感谢您的反馈!
    • 我想我剩下的问题是协议的用途。在我看来,它在故事中没有任何作用。为什么这不只是一个通用类,故事的结尾?您可以删除协议并删除该类对协议的采用,并且该类只是编译并执行您想要的操作。
    • 另外,返回 index ?? NotFound 不是 Swift 的。这就是为什么上帝给了我们可选的。表示您没有找到某物的方式与index 发出的信号完全相同。
    • 你在这两种情况下都是正确的。正如我在这个线程开头所说的那样,我正在尝试学习泛型并且已经成功地使事情变得过于复杂。事情现在清楚多了。
    • 我想知道我自己对泛型的解释是否会有所帮助。我对他们的解释和动机与大多数人教他们的方式有点不同。 apeth.com/swiftBook/ch04.html#_generics 只是有点过时了。
    猜你喜欢
    • 2018-02-28
    • 1970-01-01
    • 1970-01-01
    • 2018-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多