我有以下SWIFT代碼:實施`Array`&`ArraySlice`擴展與協議代替
extension Array {
typealias EqualTest = (Iterator.Element, Iterator.Element) -> Bool
func groupSplitIndices(withEqualTest equal: EqualTest) -> [Index] {
return indices.groupSplitIndices(withEqualTest: {equal(self[$0], self[$1])})
}
}
extension ArraySlice {
typealias EqualTest = (Iterator.Element, Iterator.Element) -> Bool
func groupSplitIndices(withEqualTest equal: EqualTest) -> [Index] {
return indices.groupSplitIndices(withEqualTest: {equal(self[$0], self[$1])})
}
}
extension CountableRange {
typealias EqualTest = (Element, Element) -> Bool
func groupSplitIndices(withEqualTest equal: EqualTest) -> [Element] {
// Implementation omitted here.
// For details see "Background" at the end of the question.
}
}
而不是具有相同代碼延伸Array
和ArraySlice
,是否有協議我可以擴展,這將實現相同的結果?
基本上,我想擴展任何集合,其中關聯的類型Indices
是CountableRange
。
嘗試在通用實現
我試過很多方法來表達這一點,但我還沒有找到一種方法,使編譯它。
嘗試1
extension RandomAccessCollection {
typealias EqualTest = (Iterator.Element, Iterator.Element) -> Bool
func groupSplitIndices(withEqualTest equal: EqualTest) -> [Index] {
// Error on next line…
return indices.groupSplitIndices(withEqualTest: {equal(self[$0], self[$1])})
}
}
這種嘗試給予2個錯誤:
Value of type 'Self.Indices' has no member 'groupSplitIndices'
Closure use of non-escaping parameter 'equal' may allow it to escape
(我認爲第二個錯誤是斯威夫特越來越糊塗。)
嘗試2
extension RandomAccessCollection where Indices: CountableRange {
// Implementation omitted.
}
給出錯誤:
Reference to generic type 'CountableRange' requires arguments in <...>
嘗試3
extension RandomAccessCollection where Indices: CountableRange<Int> {
// Implementation omitted.
}
給出錯誤:
Type 'Indices' constrained to non-protocol type 'CountableRange'
背景
這裏的實施groupRanges(withEqualTest:)
上CountableRange
擴展被省略上述。算法,它做什麼,它的大O成本,討論in this question。
我試圖實現類似的擴展RandomAccessCollection
,但沒有太多的運氣。
extension CountableRange {
typealias EqualTest = (Element, Element) -> Bool
func groupRanges(withEqualTest equal:EqualTest) -> [CountableRange] {
let groupIndices = groupSplitIndices(withEqualTest: equal)
return groupIndices.indices.dropLast().map {groupIndices[$0]..<groupIndices[$0+1]}
}
func groupSplitIndices(withEqualTest equal: EqualTest) -> [Element] {
var allIndexes = [lowerBound]
allIndexes.append(contentsOf: interiorGroupSplitIndices(withEqualTest: equal))
allIndexes.append(upperBound)
return allIndexes
}
func interiorGroupSplitIndices(withEqualTest equal: EqualTest) -> [Element] {
var result = Array<Element>()
var toDo = [self]
while toDo.count > 0 {
let range = toDo.removeLast()
guard
let firstElement = range.first,
let lastElement = range.last,
firstElement != lastElement,
!equal(firstElement, lastElement) else {
continue;
}
switch range.count {
case 2:
result.append(lastElement)
default:
let midIndex = index(firstElement, offsetBy: range.count/2)
toDo.append(range.suffix(from: midIndex))
toDo.append(range.prefix(through: midIndex))
}
}
return result
}
}
它是否可以實現RandomAccessCollection而不是CountableRange的代碼? - 然後,您可以輕鬆地將來自任意RandomAccessCollection的調用轉發給其索引。 –
@MartinR謝謝 - 我已經增加了一些關於這個問題。 – Benjohn