繁体   English   中英

具有约束类型的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协议的情况添加一些默认功能,即直接返回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)
    }
}

简答:将下标方法的返回类型更改为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方法声明为

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

其中Self.IndexSelf.Element是`Collection的关联类型。 用你的代码

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

编译器推断Self.IndexObject.Index ,但没有关系Self.ElementObject.Element (其由返回object[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.ElementDDCDataSource.Element 推断Object.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

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

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

正如苹果所说 :数组符合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

    }

暂无
暂无

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

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