Этот вопрос связан с видео @ twostraws о том, как Apple реализовала Sequence.map
Вот как Apple это делает:
@inlinable
public func map<T>(
_ transform: (Element) throws -> T
) rethrows -> [T] {
let initialCapacity = underestimatedCount
var result = ContiguousArray<T>()
result.reserveCapacity(initialCapacity)
var iterator = self.makeIterator()
// Add elements up to the initial capacity without checking for regrowth.
for _ in 0..<initialCapacity {
result.append(try transform(iterator.next()!))
}
// Add remaining elements, if any.
while let element = iterator.next() {
result.append(try transform(element))
}
return Array(result)
}
Я понимаю блестящее использование underestimatedCount
, чтобы зарезервировать емкость массива до начала добавления, но я не понимаю гайки и болты петель for _ in
и while let
внизу .
Почему эта реализация цикла более оптимальна, чем простой вызов:
while let element = iterator.next() {
result.append(try transform(element))
}
для всего Sequence
?
------ РЕДАКТИРОВАТЬ: Дальнейшие исследования ------
Я понимаю причину использования while let
, for _ in
и принудительного развертывания в изоляции. Этот вопрос касается того, почему этот подход использования обоих по одному оптимален в этом сценарии.
Что еще более запутанно, так это то, что при просмотре большего количества кода Apple вы видите, что filter
использует while let
для итерации своих элементов, но сокращает использование for element in self
вместо создания итератора.
Так много загадок!