【问题标题】:Generic protocol inside generic protocol in Swift 3Swift 3 中泛型协议中的泛型协议
【发布时间】:2017-04-07 21:39:09
【问题描述】:

我想在 Swift 中为 Tree 创建一个接口(协议)。这棵树将使用 TreeNodes 的接口(协议)。但是所有这些接口都应该是通用的。理想情况下,我想要这样的东西:

protocol TreeNodeInterface {
    associatedtype T: ElementInterface

    var value: T { get set }

    // ... some other methods
 }

protocol TreeInterface {
    var rootNode: TreeNodeInterface<T>? { get }

    func clean()

    // .. some other methods
}

class Tree<T: ElementInterface>: TreeInterface {
    var root: TreeNodeInterface<T>?

    var rootNode: TreeNodeInterface<T>? {
        get {
            return root
        }
    }

    func clean() {

    }
}

例如,我将拥有从 TreeInterface 继承的类 Tree,并且我可以使用任何类型(Int、String、CustomClass 等)初始化该树,这样每个节点都会将该类型作为值。

我设法用面向对象编程做到了这一点,但不能用面向协议编程做到这一点

Swift 不允许我这样做。有人可以在这里帮助我吗? 谢谢

【问题讨论】:

  • 目前还不清楚您从这里的协议中得到了什么(要让它工作并不简单,所以值得确保它是值得的)。你真的期待TreeInterface 的多种实现吗?第二个实现会是什么样子?如果没有协议(或类),这相当简单。
  • 下一个协议可以是BinaryTreeInterface、BinarySearchTreeInterface、AVLTreeInterface等。 TreeNodeInterface 也一样
  • 我不明白“BinarySearchTreeInterface”是怎样一个协议。这听起来像是一个特定的实现(也许这就是你在这里的真正意思)。而ElementInterface的要求是什么?这造成了很多复杂性。我想你想看看Collection 是如何实现的,并按照相同的思路创建一个Tree 协议。如前所述,我认为这已经变得过于复杂了,Swift 会倾向于在过于复杂的协议上与你抗衡。例如,如果rootNode 只返回T 而不是TreeNodeInterface,那么这一切都会大大简化。
  • “面向协议”并不意味着“为系统的每个部分和子部分创建一个协议”。这可能是这里的混乱。同样,Collection 是最好的起点。从它构建到您的 Tree 接口(在 Swift 中,它只是称为 Tree,而不是 TreeInterface)。
  • 是的,伙计们,你是对的。我把事情弄得太复杂了。感谢您的回答。

标签: swift generics protocols


【解决方案1】:

我认为您在协议方面做得太多了。您最大的问题是,如果该协议具有关联类型(或 Self 要求),则您无法创建具有协议类型的变量。通过用泛型替换这些定义,我得到了这样的结果:

protocol TreeNodeInterface {
    associatedtype Element: ElementInterface

    var value: Element { get set }

    // ... some other methods
}

protocol TreeInterface {
    associatedtype Node: TreeNodeInterface

    var rootNode: Node? { get }

    func clean()

    // .. some other methods
}

class Tree<T: TreeNodeInterface>: TreeInterface {
    typealias Node = T
    var rootNode: T?

    init() {}

    func clean() {

    }
}

这可以编译,但现在你必须弄清楚如何初始化它。下一步是创建一个符合TreeNodeInterface 的类型:

struct TreeNode<T: ElementInterface>: TreeNodeInterface {
    typealias Element = T
    var value: T
}

这看起来与协议惊人地相似,但没关系。现在让我们初始化Tree

// Assuming that Int conforms to ElementInterface
let tree = Tree<TreeNode<Int>>()

唷! 那是很多工作,我认为其中大部分是不必要的。你真的需要TreeNodeInterfaceTreeInterface 吗?我会争辩说你没有。如果您改为使用具体类型,可能会如下所示:

struct TreeNode<T: ElementInterface> {
    var value: T
}

class Tree<T: ElementInterface> {
    var root: TreeNode<T>?

    init() {}

    func clean() {

    }
}

let tree = Tree<Int>()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-09
    相关资源
    最近更新 更多