Используя вспомогательную функцию (первоначально определенный в Converting a C-style for loop that uses division for the step to Swift 3)
public func sequence<T>(first: T, while condition: @escaping (T)-> Bool, next: @escaping (T) -> T) -> UnfoldSequence<T, T> {
let nextState = { (state: inout T) -> T? in
// Return `nil` if condition is no longer satisfied:
guard condition(state) else { return nil }
// Update current value _after_ returning from this call:
defer { state = next(state) }
// Return current value:
return state
}
return sequence(state: first, next: nextState)
}
вы можете написать цикл, как
let num = 1000
for i in sequence(first: 5, while: { num/$0 > 0 }, next: { $0 * 5 }) {
print(i)
}
Более простое решение было бы в то время как петля:
var i = 5
while num/i > 0 {
print(i)
i *= 5
}
, но преимуществом первого решения является то, что область действия переменной цикла ограничена телом цикла и что переменная цикла является константой.
Swift 3.1 обеспечит prefix(while:)
method for sequences, , а затем вспомогательная функция больше не является необходимой:
let num = 1000
for i in sequence(first: 5, next: { $0 * 5 }).prefix(while: { num/$0 > 0 }) {
print(i)
}
Все выше решений является «эквивалентен» данным циклом C. Тем не менее, все они могут погибнуть, если num
находится недалеко от Int.max
и $0 * 5
переполнение. Если это проблема, вы должны проверить , если $0 * 5
подходит для целочисленного диапазона до, выполняющего умножение.
На самом деле, что делает цикл проще - по крайней мере, если мы предположим, что num >= 5
так, что цикл выполняется по крайней мере один раз:
for i in sequence(first: 5, next: { $0 <= num/5 ? $0 * 5 : nil }) {
print(i)
}
Если мы говорим о целых числах, это не 'num/i> 0' то же самое, что и запись' num> i'? – Sulthan
@Sulthan Нет, рассмотрим 'num = 5' &' i = 5', а также 'num = 5' &' i = -5' – Hamish
плюс вам все равно придется использовать i в условии цикла for – alex