在Swift中采用CollectionType(Collection)

时间:2016-08-07 02:43:23

标签: swift swift3

我正在编写图形库以在图表中显示数据。由于我所做的大多数项目往往都有大量学习组件,因此我决定创建一个通用类型的结构来管理我的数据集DataSet<T: Plottable>(请注意Plottable也是Comparable })。

在尝试符合MutableCollectionType时,我遇到了错误。我想使用sort()的默认实现,但编译器在尝试使用排序函数时会出现以下错误。

  

对成员'sort()'

的模糊引用

这是一个代码示例:

var data = DataSet<Int>(elements: [1,2,3,4])
data.sort() //Ambiguous reference to member 'sort()'

编译器建议两个候选人,但实际上不会将它们显示给我。请注意,如果我在结构上显式实现sort(),编译器错误就会消失。

但更大的问题仍然存在。我没有看到我希望默认实现提供什么?或者我是否遇到了Swift 3中的一个错误(这种情况很少发生......通常我忽略了一些事情)。

这是结构的平衡:

struct DataSet<T: Plottable>: MutableCollection, BidirectionalCollection {
typealias Element = T
typealias Iterator = DataSetIterator<T>
typealias Index = Int

/**
 The list of elements in the data set. Private.
*/
private var elements: [Element] = []

/**
 Initalize the data set with an array of data.
 */
init(elements data: [T] = []) {
    self.elements = data
}

//MARK: Sequence Protocol
func makeIterator() -> DataSetIterator<T> {
    return DataSetIterator(self)
}

//MARK: Collection Protocol
subscript(_ index:DataSet<T>.Index) -> DataSet<T>.Iterator.Element {
    set {
        elements[index] = newValue
    }
    get {
        return elements[index]
    }
}

subscript(_ inRange:Range<DataSet<T>.Index>) -> DataSet<T> {
    set {
        elements.replaceSubrange(inRange, with: newValue)
    }
    get {
        return DataSet<T>(elements: Array(elements[inRange]))
    }
}

//required index for MutableCollection and BidirectionalCollection
var endIndex: Int {
    return elements.count
}
var startIndex: Int {
    return 0
}
func index(after i: Int) -> Int {
    return i+1
}
func index(before i: Int) -> Int {
    return i-1
}

mutating func append(_ newElement: T) {
    elements.append(newElement)
}

//    /**
//     Sorts the elements of the DataSet from lowest value to highest value.
//     Commented because I'd like to use the default implementation.
//     - note: This is equivalent to calling `sort(by: { $0 < $1 })` 
//     */
//    mutating func sort() {
//        self.sort(by: { $0 < $1 })
//    }
//    
//    /**
//     Sorts the elements of the DataSet by an abritrary block.
//     */
//    mutating func sort(by areInIncreasingOrder: @noescape (T, T) -> Bool) {
//        self.elements = self.elements.sorted(by: areInIncreasingOrder)
//    }

/**
 Returns a `DataSet<T>` with the elements sorted by a provided block.

 This is the default implementation `sort()` modified to return `DataSet<T>` rather than `Array<T>`.

 - returns: A sorted `DataSet<T>` by the provided block.
 */
func sorted(by areInIncreasingOrder: @noescape (T, T) -> Bool) -> DataSet<T> {
    return DataSet<T>(elements: self.elements.sorted(by: areInIncreasingOrder))
}

func sorted() -> DataSet<T> {
    return self.sorted(by: { $0 < $1 })
}
}

1 个答案:

答案 0 :(得分:3)

您的DataSet是BidirectionalCollection。您尝试使用的sort()需要RandomAccessCollection。您需要添加的最重要的事情是Indicies typealias。

typealias Indices = Array<Element>.Indices

这是我的类型版本:

protocol Plottable: Comparable {}
extension Int: Plottable {}

struct DataSet<Element: Plottable>:  MutableCollection, RandomAccessCollection {
    private var elements: [Element] = []

    typealias Indices = Array<Element>.Indices

    init(elements data: [Element] = []) {
        self.elements = data
    }

    var startIndex: Int {
        return elements.startIndex
    }

    var endIndex: Int {
        return elements.endIndex
    }

    func index(after i: Int) -> Int {
        return elements.index(after: i)
    }

    func index(before i: Int) -> Int {
        return elements.index(before: i)
    }

    subscript(position: Int) -> Element {
        get {
            return elements[position]
        }
        set {
            elements[position] = newValue
        }
    }

    subscript(bounds: Range<Int>) -> DataSet<Element> {
        get {
            return DataSet(elements: Array(elements[bounds]))
        }
        set {
            elements[bounds] = ArraySlice(newValue.elements)
        }
    }
}

var data = DataSet(elements: [4,2,3,1])
data.sort()
print(data.elements) // [1,2,3,4]

如果你不想要迭代器,你实际上并不需要它。如果你实现Collection,Swift会自动给你Sequence。