Swift 关联类型受限于集合的协议扩展,不能使用下标

Swift Protocol Extension with AssociatedType Constrained to Collection, Can't Use Subscript

我正在尝试编写一个符合集合协议的协议,它有一个 associatedType - Object 和一个 属性 对象。

protocol DDCDataSource: Collection
{
    associatedtype Object
    var object: Object {get set}
}

我想为 Object 也符合 Collection 协议的情况添加一些默认功能,即直接 return Object 实现这些必需的 Collection 属性和函数。除了 Collection 对下标的要求外,这似乎都有效。

Cannot subscript a value of type 'Self.Object' with an index of type 'Self.Object.Index'

extension DDCDataSource where Object: Collection
{
    typealias Index = Object.Index

    var startIndex: Object.Index {
        get {
            return object.startIndex
        }
    }

    var endIndex: Object.Index {
        get {
            return object.endIndex
        }
    }

    subscript(position: Object.Index) -> Element
    {
        return object[position]
    }

    func index(after i: Object.Index) -> Object.Index {
        return object.index(after: i)
    }
}

首先,我认为你应该定义Element,

其次,您使用 object[position], Object Conforms To Collection ,但它不是 Collection Types 。显然不是Array。

As apple says: array conforms to CustomDebugStringConvertible / CustomReflectable / CustomStringConvertible / CVarArg /Decodable / Encodable / ExpressibleByArrayLiteral /MutableCollection /RandomAccessCollection / RangeReplaceableCollection

我觉得extension DDCDataSource where Object: Array比较好

数组中的元素应Element定义。只是提示。

试试这个:

subscript(position:Object.Index) -> Element
    {
        var element: Element
        guard let elementObject = object[position] else {
            //handle the case of 'object' being 'nil' and exit the current scope
        }
        element = elementObject as! Element

    }

简答:更改下标方法的return类型 至 Object.Element

subscript(position: Object.Index) -> Object.Element {
    return object[position]
}

或添加类型别名(与为 Index 类型所做的方式类似)

typealias Element = Object.Element

subscript(position: Object.Index) -> Element {
    return object[position]
}

这使得代码编译并 运行 符合预期。


解释:Collectionsubscript method声明为

subscript(position: Self.Index) -> Self.Element { get }

其中 Self.IndexSelf.Element 是关联类型 的`集合。使用您的代码

subscript(position: Object.Index) -> Element {
    return object[position]
}

编译器将 Self.Index 推断为 Object.Index,但是有 Self.ElementObject.Element 之间没有关系(这是 return 由 object[position] 编辑)。错误变得更加明显 如果你添加一个显式转换:

subscript(position: Object.Index) -> Element {
    return object[position] as Element
}

现在编译器报错了

error: 'Self.Object.Element' is not convertible to 'Self.Element'; did you mean to use 'as!' to force downcast?

正确的解决方案是不是强制转换而是编译器 通过添加类型别名知道 Self.ElementObject.Element 或者通过更改 return 类型

subscript(position: Object.Index) -> Object.Element {
    return object[position]
}

以便编译器 推断 DDCDataSource.ElementObject.Element.


完整的独立示例:(Swift 4,Xcode 9 beta 6)

(请注意,对于只读计算,您可以省略 get 关键字 属性。)

protocol DDCDataSource: Collection {
    associatedtype Object
    var object: Object { get set }
}

extension DDCDataSource where Object: Collection {
    var startIndex: Object.Index {
        return object.startIndex
    }

    var endIndex: Object.Index {
        return object.endIndex
    }

    subscript(position: Object.Index) -> Object.Element {
        return object[position]
    }

    func index(after i: Object.Index) -> Object.Index {
        return object.index(after: i)
    }
}

struct MyDataSource: DDCDataSource {
    var object = [1, 2, 3]
}

let mds = MyDataSource()
print(mds[1]) // 2

for x in mds { print(x) } // 1 2 3