问题是编译器不知道你的扩展是针对二维数组的——它只知道它是针对集合数组的。因此关联类型IndexDistance 和Index 不一定是Int。
因此,解决方案是限制您的扩展,使Element 的IndexDistance 和Index 是 类型为Int。这将让您形成0..<count 范围,因为count 现在的类型为Int (IndexDistance) – 您将能够使用Ints 为map(_:) 中的元素下标(如下标需要 Index)。
(一旦支持concrete same-type requirements,这将是微不足道的,因为您可以简单地将Element 限制为Array,但这还不可能。)
您还应该注意,您的约束 Element.Iterator.Element: Collection 不正确,因为这会将扩展限制为 3D 集合数组(元素是集合的数组,其中该集合的元素是集合)。
最后,您可能必须定义一个 typealias 来表示二维数组的“内部元素”类型,因为 Swift 目前有 some limitations when working with nested types directly,例如在创建该类型的空二维数组时。
因此,您当前方法的工作版本应如下所示:
extension Array where Element: Collection, Element.Index == Int, Element.IndexDistance == Int {
private func rotate() -> [[Element.Iterator.Element]] {
typealias InnerElement = Element.Iterator.Element
// in the case of an empty array, simply return an empty array
if self.isEmpty { return [] }
let length = self[0].count
var returnValue = [[InnerElement]](repeating: [InnerElement](), count: length)
for index in 0..<length {
returnValue[index] = self.map{ $0[index] }.reversed()
}
return returnValue
}
}
正如@MartinR points out below,可以通过使用嵌套的map(_:) 大大简化,消除了typealias 的需要,因为我们不再需要创建“结果”数组:
private func rotate() -> [[Element.Iterator.Element]] {
if self.isEmpty { return [] }
let length = self[0].count
return (0..<length).map { index in
self.map { $0[index] }.reversed()
}
}
尽管请注意,将扩展限制为仅与 Int 索引一起使用并不是绝对必要的(但是没有实际区别,因为您只打算将其与 2D 数组一起使用)。另一种选择是直接遍历内部集合的indices。
为此,您只需约束您的扩展,使内部集合的Indices 具有与集合的Index 相同类型的Elements(在Array 的情况下) , Indices 是 CountableRange<Int>):
extension Array where Element: Collection, Element.Indices.Iterator.Element == Element.Index {
private func rotate() -> [[Element.Iterator.Element]] {
if self.isEmpty { return [] }
return self[0].indices.map { index in
self.map { $0[index] }.reversed()
}
}
}