【问题标题】:Swift Protocol Extension with AssociatedType Constrained to Collection, Can't Use SubscriptSwift 协议扩展,AssociatedType 被限制为集合,不能使用下标
【发布时间】:2017-09-09 08:10:15
【问题描述】:

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

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

【问题讨论】:

  • 请不要使用图片,而是添加代码sn-p。
  • 我添加了标签 swift 3.2 因为它是 Xcode 9 特有的。在 Xcode 8 上你会有 "Use of undeclared type 'Element'".
  • extension DDCDataSource where Object: RandomAccessCollection,感觉好多了。
  • return object[position] as! Element
  • @Cœur:不,这会在运行时崩溃。

标签: swift generics swift-protocols protocol-extension swift3.2


【解决方案1】:

简答:更改下标方法的返回类型 给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 之间没有关系(即 由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.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

【讨论】:

    【解决方案2】:

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

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

    作为apple says: 数组 符合 CustomDebugStringConvertible / CustomReflectable / CustomStringConvertible / CVarArg /Decodable / Encodable / ExpressibleByArrayLiteral /MutableCollection /RandomAccessCollection / RangeReplaceableCollection

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

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

    【讨论】:

    • 这是一个协议,目标是让它非常通用,并允许使用它的类/结构来定义元素。我还希望 Object 适用于所有集合类型,而不仅仅是数组。
    • 是的,协议很简短。我试图简化它。有点分而治之。谢谢你。我是 Swift 4 的新手。Element 对我来说似乎很奇怪。我得到了一些,虽然不如 Martin R。没有反对票很好。
    【解决方案3】:

    试试这个:

    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
    
        }
    

    【讨论】:

    • 真的可以编译吗? object[position] 不是可选的。
    • 是的,它不是可选的——但省略了保护语句,只返回 object[position] as!元素会编译。至于它是否会崩溃——我还没有尝试实际运行它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-30
    相关资源
    最近更新 更多