简体   繁体   English

约束协议的关联类型本身

[英]Constrain protocol's associated type itself

I'm trying to create generic CollectionView datasource. 我正在尝试创建通用的CollectionView数据源。 I have two protocols, first - some abstract cell, the second indicates that conforming class could be presented by some abstract cell and should contain only associated type referencing that cell. 我有两个协议,第一个-一个抽象单元格,第二个表明某个抽象单元格可以表示符合类,并且应该只包含引用该单元格的关联类型。 Their implementation could look like this: 它们的实现可能如下所示:

protocol EntityPresentingCell {

    // entity that should be presented in this cell
    associatedtype T

    static var CellReuseID: String { get }

    // takes object and fill UI with data
    func populate(with object: T)
}

protocol CellPresentable {

    // cell that should present this entity
    // I need to constrain it
    associatedtype Cell: EntityPresentingCell // where Cell.T == Self
}

class CollectionViewDataSource<T: CellPresentable>: NSObject, UICollectionViewDataSource {

    var items: [T]

    init(items: [T]) {
        self.items = items
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return items.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: T.Cell.CellReuseID, for: indexPath)

        // compiler error here since, obviously, T.Cell.T not constrained to T itself
        (cell  as! T.Cell).populate(with: items[indexPath.item])
        return cell
    }

}

At the point of usage it could look like this: 在使用时,它可能看起来像这样:

class SomeEntity: CellPresentable {
    typealias Cell = SomeEntityCell

    var someValue = "someValue"
}

class SomeEntityCell: EntityPresentingCell {

    static var CellReuseID: String = "SomeID"

    @IBOutlet weak var label: UILabel!

    func populate(with object: SomeEntity) {
        label.text = object.someValue
    }

}

The problem with this code is that I can not constrain (and thus be sure at compile time that) CellPresentable.Cell.T to be equal to CellPresentable itself (like in example). 这段代码的问题是,我无法约束CellPresentable.Cell.T(因此确保在编译时确保它)等于CellPresentable本身(例如示例)。 It is clearly seen with compiler error. 可以清楚地看到编译器错误。

The goal is to make pure compile-time all-sufficient code that could prove that item is presentable by given cell (again, at compile time) and I don't want to force downcasts, or any other run-time checks. 目标是制作纯粹的编译时全能代码,以证明该项目可以在给定的单元格中显示出来(再次在编译时),而我不想强制向下转换或进行任何其他运行时检查。

Is it possible? 可能吗? If so, how? 如果是这样,怎么办?

UPD: David Rodrigues answer works, but it means that mismatch (T.Cell.T != T) will be revealed only when I'm about to create CollectionViewDataSource . UPD: David Rodrigues的答案有效,但这意味着不匹配(T.Cell.T != T)仅在我要创建CollectionViewDataSource时才会显示。 I want it to happen exactly when I define my entity's conformance to EntityPresentingCell protocol. 我希望在定义我的实体对EntityPresentingCell协议的符合性时发生。 In other words, compiler should complain when I write something like 换句话说,当我写类似的东西时,编译器应该抱怨

class SomeEntity: CellPresentable {
    typealias Cell = SomeWrongEntityCell

    var someValue = "someValue"
}

but not when I create CollectionViewDataSource instance. 但是当我创建CollectionViewDataSource实例时却没有。 It's entity responsibility to ensure cell type, not the creator of CollectionViewDataSource . 确保单元格类型是实体的责任,而不是CollectionViewDataSource的创建者。

Swift 4 Update Swift 4更新

You can now add the where Cell.T == Self constraint to the associated type, so you can indeed now just say: 现在,您可以将where Cell.T == Self约束添加到关联的类型,因此,您现在确实可以说:

protocol CellPresentable {
    associatedtype Cell : EntityPresentingCell where Cell.T == Self
}

Swift 3 迅捷3

Currently, it's not possible to add any further constraints to associated types besides what they are required to conform to. 当前,除了需要遵守的约束之外,不可能对关联的类型添加任何其他约束。

However, now that SE-0142: Permit where clauses to constrain associated types has been accepted, being able to add where clauses to associated types will be possible in a future version of Swift. 但是,现在SE-0142:允许约束关联类型的where子句已被接受,在以后的Swift版本中,可以在关联类型中添加where子句。

You should just be able to say: 应该只能说:

protocol CellPresentable {
    associatedtype Cell : EntityPresentingCell where Cell.T == Self
}

Although until this is implemented, David's solution of adding the generic constraint where T.Cell.T == T is probably about as good as you're going to get. 尽管在实现之前, David的添加通用约束( where T.Cell.T == T 的解决方案)的解决方案可能与您将要获得的效果where T.Cell.T == T

您可以约束T.Cell.T等于T

class CollectionViewDataSource<T: CellPresentable>: NSObject, UICollectionViewDataSource where T.Cell.T == T

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

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