В версии 3.0 языка Swift решили убрать и, таки, убрали некоторый синтаксис языка C. В частности, убрали вид цикла for, принятый в языке C. Убрали вместе с замечательными операциями ++ и --. К чему это нас приводит? Это приводит к тому, что простой цикл вида:
for var i = 0; i < N; ++i {
rint("\(i)")
}
использовать нельзя. Но тогда что в замен? В замен Swift давно предлагает диапазоны. По планам разработчиков, все пользователи Swift должны были писать так:
for i in 0..<10 {
print("\(i)")
}
Вполне хороший синтаксис. Но может ли он покрыть все возможности старого? Хотя бы все важные возможности. Например, что делать, когда надо посчитать значения функции на заданном отрезке с некоторым шагом? В синтаксисе C можно записать так:
for var x = a; x <= b; x += h {
print("y(\(x)) = \(x*x)")
}
Прежде, чем дать решение поставленной задачи, разберем, какие возможности есть у диапазонов и как они покрывают задачи, решаемые циклом for. Уже показан пример перебора элементов из возрастающего диапазона. Но у нас есть и убывающий:
for var i = 9; i >= 0; i-- {
print(i)
}
Такое решение задачу не решит:
for i in 9...0 {
print("\(i)")
}
Будет выдана ошибка времени исполнения, говорящая, что начало диапазона не должно быть больше конца. Для прохождения в обратном направлении надо применить функцию reversed():
for i in (0..<10).reversed() {
print("\(i)")
}
Для случая с произвольным шагом вроде:
for var i = 0; i < 10; i += 2 {
print(i)
}
можно написать следующее:
for i in stride(from: 0, to: 10, by: 2) {
print(i)
}
Такая запись:
for i in 0.stride(to: 10, by: 2) {
print(i)
}
пока не доступна и верно доступна не будет.
Этот вариант позволяет решить поставленную выше задачу таким образом:
for x in stride(from: a, to: b, by: h) {
print("y(\(x)) = \(x*x)")
}
Таким образом понятно, что новый синтаксис перекрывает основные возможности оператора for в синтаксисе C. Однако, ещё не рассмотрен вопрос прохождения по элементам массива. Задачи такого рода можно и, вероятно, нужно решать особым способом – перебором элементов коллекции. Рассмотрим на примерах. Перепишем следующий пример в новом синтаксисе:
let arr = [2, 3, 45, 6, 8, 83, 100]
for var i = 0; i < arr.count; i++ {
print(arr[i])
}
С применением цикла:
let arr = [2, 3, 45, 6, 8, 83, 100]
// В прямом направлении
for el in arr{
print(el)
}
// В обратном направлении
for el in arr.reversed(){
print(el)
}
В случае, если нам требуются работать с индексами коллекции следующий вариант не является лучшим:
for i in 0..<arr.count {
print(arr[i])
}
В замен используем такой подход:
for i in arr.indices {
print(arr[i])
}
for (i, el) in arr.enumerated() {
print("\(i) \(el)")
}
Вроде всё хорошо и охвачены все задачи, коие требуется решать наиболее часто. И тут мы следует вспомнить, что в Swift добавлены некоторые черты функционального языка. И работа с коллекциями одно из тех мест, где уместно их использовать. Например, таким образом:
arr.forEach{
print( $0 )
}
arr.reversed().forEach{
print( $0 )
}
arr.enumerated().forEach {
(i, el) in
print("\(i) \(el)")
}
Да, у нас есть набор удобных функций над коллекциями народе map, flatMap, filter, reduce. Так что не забываем ими пользоваться.