Swift 4. 使用 PAT。允许相互引用的协议吗?我收到一个我不明白的错误

Swift 4. Using PATs. Are protocols which reference each other allowed? I'm getting an error I don't understand

在下面的代码中,我在一个简单的 Graph 项目中设置了顶点和边的协议。顶点引用边,边引用顶点。在 neighbours() 函数中,我在 edges 数组上调用 map() 并收到此错误:

'map' produces '[T]', not the expected contextual result type '[Self.VertexType]'.

import Foundation

protocol EdgeProtocol {
    associatedtype VertexType: VertexProtocol
    var from : VertexType { get set }
    var to : VertexType { get set }
    init(from: VertexType, to:VertexType)
}

protocol VertexProtocol  {
    associatedtype EdgeType: EdgeProtocol
    associatedtype VertexType: VertexProtocol
    var id: String { get set }
    var edges: [EdgeType] { get set }
    func neighbours() -> [VertexType]
}

extension VertexProtocol {
    func neighbours() -> [VertexType] {
        return edges.map { [=11=].to }  // 'map' produces '[T]', not the expected
                                    //  contextual result type '[Self.VertexType]'
    }
}

struct Edge: EdgeProtocol {
    typealias VertexType = Vertex   // leave out -> no compile error
    var from: Vertex
    var to: Vertex
    init(from: Vertex, to:Vertex) {
        self.from = from
        self.to = to
    }
}

class Vertex: VertexProtocol {
    typealias VertexType = Vertex   // leave out -> compile error
    typealias EdgeType = Edge       // leave out -> no compile error

    var id: String
    var edges = [Edge]()
    init(name: String) { id = name }
}

我的代码 "knows" edges[Vertex:VertexProtocol] 类型,但是 map() 将其解释为 [T]。这是因为 Swift 4 不允许协议之间的交叉引用还是其他原因?我必须承认我并不真正理解 PAT(具有关联类型的协议),正如我的评论行所表明的那样。任何指导表示赞赏

问题是虽然edges符合EdgeProtocol,并且EdgeProtocol包含一个VertexType关联类型,编译器无法知道这将是与 VertexProtocol's VertexType associated type. Both protocols' VertexType 相同的类型将符合 VertexProtocol,但它们不一定是同一类型。因此 edges.map { [=20=].to } returns [EdgeType.VertexType],但是你的函数被声明为 return [Self.VertexType],所以它是类型不匹配。

您可以通过明确指定两个 VertexType 相同来解决此问题。您可以在定义中这样做:

protocol VertexProtocol  {
    associatedtype VertexType
    associatedtype EdgeType: EdgeProtocol where EdgeType.VertexType == VertexType
    // ...
}

或者,如果这不切实际,您可以限制扩展名:

extension VertexProtocol where EdgeType.VertexType == VertexType {
    func neighbours() -> [VertexType] {
        return edges.map { [=11=].to }
    }
}

这两种方法中的任何一种都应该生成可编译的代码。