仅使用下标使自定义类型符合RandomAccessCollection

Conform a custom type to RandomAccessCollection with only a subscript(仅使用下标使自定义类型符合RandomAccessCollection)

本文介绍了仅使用下标使自定义类型符合RandomAccessCollection的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我通常实现行为类似数组的类型,如下所示:

struct Dataset: RandomAccessCollection {
    let ids: [Int]
    // Other properties and methods...

    // Boilerplate
    var startIndex: Int { ids.startIndex }
    var endIndex: Int { ids.endIndex }
    func formIndex(after i: inout Int) { i += 1 }
    func formIndex(before i: inout Int) { i -= 1 }

    subscript(index: Int) -> Int {
        // Dummy example, could be more complex and return a different type
        return ids[index]
    }
}

问题是我需要为RandomAccessCollection一致性编写每个时间段的样板代码。我想要一个协议或机制将样板减少到只有一个或两个要求:

  • 用于推断协议要求的底层RandomAccessCollection(如我示例中的ids属性)(startIndexendIndexformIndex))
  • 完成剩余要求的下标

此机制类似于当前在Pytorch中完成数据集继承的方式:只是具有__len____getitem__要求。

我想出这样的草稿:

protocol ArrayProtocol: RandomAccessCollection where Index == BaseCollection.Index {
    associatedtype BaseCollection: RandomAccessCollection
    
    var baseCollection: BaseCollection { get set }
    subscript(index: Index) -> Element { get set }
}

// Provide the default implementation of the RandomAccessCollection protocol
extension ArrayProtocol {
    var startIndex: Index { baseCollection.startIndex }
    var endIndex: Index { baseCollection.endIndex }
    func formIndex(after i: inout Index) { baseCollection.index(after: i) }
    func formIndex(before i: inout Index) { baseCollection.index(before: i) }
}

此协议将按如下方式使用:

struct Dataset: ArrayProtocol {
    let ids: [Int]
    // Other properties and methods...

    // No more boilerplate
    var baseCollection: [Int] { ids }

    subscript(index: Int) -> Int {
        // Dummy example, could be more complex and return a different type
        return ids[index]
    }
}

但我找不到方法使其正常工作,而且我觉得关联类型不是很好的设计模式。

有解决此问题的想法吗?

编辑:where Index == BaseCollection.Index子句不是必需的,下标可以具有与基础集合不同的Index类型。

推荐答案

关联类型通常用于泛型类型(通常是集合的元素)。向其添加关联的类型typealias BaseCollection = [Int]并删除Set的下标要求。

protocol ArrayProtocol: RandomAccessCollection where Index == BaseCollection.Index {
    associatedtype BaseCollection: RandomAccessCollection
    var baseCollection: BaseCollection { get set }
    subscript(index: Index) -> Element { get }
}

extension ArrayProtocol {
    var startIndex: Index { baseCollection.startIndex }
    var endIndex: Index { baseCollection.endIndex }
    func formIndex(after i: inout Index) { baseCollection.index(after: i) }
    func formIndex(before i: inout Index) { baseCollection.index(before: i) }
}

struct Dataset: ArrayProtocol {
    typealias BaseCollection = [Int]
    var baseCollection: BaseCollection = [ ]
    subscript(index: Int) -> Int { baseCollection[index] }
}


请注意,如果要保留设置的要求subscript(index: Index) -> Element { get set },还需要确保BaseCollection也符合MutableCollection

subscript(index: Int) -> BaseCollection.Element {
    get { baseCollection[index] }
    set { baseCollection[index] = newValue } 
}

这篇关于仅使用下标使自定义类型符合RandomAccessCollection的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本文标题为:仅使用下标使自定义类型符合RandomAccessCollection

基础教程推荐