没有必要将所有这些想法局限于具体的Array
类型。
这是我的解决方案。这次讨论非常棒,因为我刚学习了RangeReplaceableCollection
。将(我认为是)最好的两个世界融合起来,我尽可能地将所有操作向下(或向上?)推进了类型层次结构。
正如@Hamish所说,下标运算符适用于远不止Array
。但是,没有必要约束索引类型,因此我们必须摆脱IndexPath
。我们总是可以用typealias Index2d = ...
来简化此操作。
extension Collection where Self.Element: Collection {
subscript(_ indexTuple: (row: Self.Index, column: Self.Element.Index)) -> Self.Element.Element {
get {
return self[indexTuple.row][indexTuple.column]
}
}
}
为什么不在最通用的层级(介于“Collection”和“RangeReplaceableCollection”之间)拥有可变版本呢?(不幸的是,我认为当我们重新定义“subscript”时getter无法继承):
extension MutableCollection where Self.Element: MutableCollection {
subscript(_ indexTuple: (row: Self.Index, column: Self.Element.Index)) -> Self.Element.Element {
get {
return self[indexTuple.row][indexTuple.column]
}
set {
self[indexTuple.row][indexTuple.column] = newValue
}
}
}
然后,如果您想要进行延迟初始化,请避免使用
init:repeatedValue
并修改
set
以具有自动初始化语义。您可以通过整合已接受答案的
fillingAppend
思想,在两个维度上陷入边界溢出并添加缺少的空元素。
当创建2D初始化程序时,为什么不以自然方式扩展
repeating
的思想呢?
extension RangeReplaceableCollection where Element: RangeReplaceableCollection {
init(repeating repeatedVal: Element.Element, extents: (row: Int, column: Int)) {
let repeatingColumn = Element(repeating: repeatedVal, count: extents.column)
self.init(repeating: repeatingColumn, count: extents.row)
}
}
例子用法:
enum Player {
case first
case second
}
class Model {
let playerGrid: Array<Array<Player>> = {
var p = [[Player]](repeating: .first, extents: (row: 10, column: 10))
p[(3, 4)] = .second
print("Player at 3, 4 is: \(p[(row: 3, column: 4)])")
return p
}()
}
_ArrayProtocol
。我猜我不再需要where
子句了?不确定... - Stefan Stefanovwhere
子句,而是直接使用Element
代替Element.Iterator.Element
,但是当我尝试执行let newSubArray = Element()
时,会出现“Element cannot be constructed because it has no accessible initiliaziers”的错误提示。我还尝试了将扩展从Array
改为Collection
,并使用Iterator.Element
代替Element
,但仍然没有成功。 - Stefan Stefanov