3

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

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

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

无法使用“Self.Object.Index”类型的索引为“Self.Object”类型的值下标

在此处输入图像描述

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)
    }
}
4

3 回答 3

6

简短回答:将下标方法的返回类型更改为Object.Element

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

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

typealias Element = Object.Element

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

这使得代码按预期编译和运行。


说明:subscript方法Collection声明为

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

whereSelf.IndexSelf.Element是 `Collection. 使用您的代码

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

编译器推断Self.Index为,但和(由 返回)Object.Index之间没有关系。如果添加显式强制转换,错误会变得更加明显:Self.ElementObject.Elementobject[position]

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

现在编译器抱怨

错误:“Self.Object.Element”不能转换为“Self.Element”;你的意思是用'as!' 强迫沮丧?

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

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
于 2017-09-10T07:54:46.747 回答
0

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

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

正如苹果所说:数组符合 CustomDebugStringConvertible / CustomReflectable / CustomStringConvertible / CVarArg /Decodable / Encodable / ExpressibleByArrayLiteral /MutableCollection /RandomAccessCollection / RangeReplaceableCollection

我认为extension DDCDataSource where Object: Array更好。

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

于 2017-09-09T11:10:48.027 回答
0

尝试这个:

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

    }
于 2017-09-09T11:20:44.103 回答