简体   繁体   English

具有约束类型的Swift协议扩展约束到集合,不能使用下标

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

I'm trying to write a protocol that conforms to the Collection Protocol, and it has an associatedType - Object and a property object. 我正在尝试编写符合集合协议的协议,它有一个associatedType - Object和一个属性对象。

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

I want to add some default functionality for the case where Object also conforms to the Collection protocol, namely just directly return Object's implementation of these required Collection properties and functions. 我想为Object也符合Collection协议的情况添加一些默认功能,即直接返回Object对这些必需Collection属性和函数的实现。 It seems like it all works except for Collection's requirement for a subscript. 除了Collection对下标的要求外,它似乎都有效。

Cannot subscript a value of type 'Self.Object' with an index of type 'Self.Object.Index' 无法使用类型为“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)
    }
}

Short answer: Change the return type of the subscript method to Object.Element 简答:将下标方法的返回类型更改为Object.Element

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

or add a type alias (in a similar way as you did for the Index type) 或添加类型别名(以与您对Index类型类似的方式)

typealias Element = Object.Element

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

That makes the code compile and run as expected. 这使得代码按预期编译和运行。


Explanation: The subscript method of Collection is declared as 说明: Collectionsubscript方法声明为

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

where Self.Index and Self.Element are associated types of `Collection. 其中Self.IndexSelf.Element是`Collection的关联类型。 With your code 用你的代码

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

the compiler infers Self.Index to be Object.Index , but there is no relation between Self.Element and Object.Element (which is returned by object[position] ). 编译器推断Self.IndexObject.Index ,但没有关系Self.ElementObject.Element (其由返回object[position] )。 The error becomes more apparent if you add an explicit cast: 如果添加显式强制转换,则错误会更明显:

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

Now the compiler complains 现在编译器抱怨了

error: 'Self.Object.Element' is not convertible to 'Self.Element'; 错误:'Self.Object.Element'不能转换为'Self.Element'; did you mean to use 'as!' 你的意思是用'as!' to force downcast? 迫使低垂?

The correct solution is not the forced cast but to make the compiler know that Self.Element is Object.Element , by adding a type alias or by changing the return type 正确的解决方案不是强制转换,而是通过添加类型别名或通过更改返回类型使编译器知道Self.ElementObject.Element

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

so that the compiler infers DDCDataSource.Element to be Object.Element . 这样编译器DDCDataSource.ElementDDCDataSource.Element 推断Object.Element


Full self-contained example: (Swift 4, Xcode 9 beta 6) 完整的自包含示例:( Swift 4,Xcode 9 beta 6)

(Note that you can omit the get keyword for read-only computed properties.) (请注意,您可以省略只读计算属性的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

Firstly, I think you should define Element , 首先,我认为你应该定义Element

Secondly, you use object[position] , Object Conforms To Collection , but it is not of Collection Types . 其次,您使用object[position] ,Object Conforms To Collection,但它不是Collection Types。 Obviously it is not Array. 显然它不是Array。

As apple says : array conforms to CustomDebugStringConvertible / CustomReflectable / CustomStringConvertible / CVarArg /Decodable / Encodable / ExpressibleByArrayLiteral /MutableCollection /RandomAccessCollection / RangeReplaceableCollection 正如苹果所说 :数组符合CustomDebugStringConvertible / CustomReflectable / CustomStringConvertible / CVarArg / Decodable / Encodable / ExpressibleByArrayLiteral / MutableCollection / RandomAccessCollection / RangeReplaceableCollection

I think extension DDCDataSource where Object: Array is better. 我认为extension DDCDataSource where Object: Array更好。

And the element in array shall be Element defined. 并且数组中的元素应该是Element定义的。 Just tips. 只是提示。

Try this: 试试这个:

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

    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM