Вместе с презентацией языка Swift Apple выложила в BookStore книгу под названием Swift Programming Language.
Оперативный перевод книги русскими умельцы успели сделать очень быстро, и сегодня я представляю его Вам.
Содержание:
-
О языке Swift
-
Тур по Swift
- Простые значения
- Контроль управления
- Функции и замыкания (closures)
- Объекты и классы
- Перечисления (enumerations) и структуры
- Протоколы и расширения
- Общие функции и типы
-
Основы
- Константы и переменные
- Аннотации(обозначения) типов
- Имена для констант и переменных
- Вывод значений констант и переменных на экран
- Комментарии
- Точка с запятой
- Целые числа (тип Integer)
- Числа с плавающей точкой
- Безопасность типов и подбор(inference) типов
- Числовые литералы
- Конвертация числовых типов
- Алиасы типов
- Логический тип (boolean)
- Кортежи (tuples)
- Опциональные значения
- Утверждения (они же ассерты, они же assertions)
-
Базовые операторы
- Оператор Присваивания
- Арифметические операторы
- Оператор Остатка
- Операторы Инкремента и Декремента
- Унарный Оператор Минус
- Унарный Оператор Плюс
- Составные операторы присваивания
- Операторы сравнения
- Тернарный условный оператор
- Операторы Диапазона
- Логические Операторы
-
Строки и символы
- Инициализация пустой строки
- Изменение строк
- Строки это тип-значение
- Работа с символами
- Подсчет символов
- Конкатенация строк и символов
- Интерполяция строк
- Сравнение строк
- ПРОПИСНЫЕ и строчные буквы в строках
- Юникод
-
Управление хода выполнения
- Циклы for
- for-in
- For-условие-инкремент
- Циклы while
- While
- Do-While
- Условные выражения
- If
- Switch
О языке Swift
Swift – это новый язык разработки iOS и OS X приложений, который включает в себя все лучшее из С и Objective C, при этом не ограничивая себя совместимостью с C.
Swift применяет безопасные практики программирования и добавляет современные функции, чтобы сделать разработку более простым, гибким и веселым занятием.
Написанный с чистого листа, Swift, опираясь на зрелый и любимый всеми фреймворк Cocoa (и CocoaTouch) – это возможность для разработчиков пересмотреть подход к разработке ПО.
Swift разрабатывался несколько лет. Компания Apple прокладывала фундамент для языка, работая над существующим компилятором, дебаггером и инфраструктурой фреймворков.
Apple упростили управление памятью, используя автоматический подсчет ссылок (ARC). Стэк фреймворков, построенный на мощном основании Foundation и Cocoa, модернизировался и стандартизировался.
Сам Objective-C эволюционировал, добавив поддержку блоков, литералы для коллекций, модули и другие функции, не нарушая существующего кода. Благодаря этой работе, Apple теперь имеет возможность представить новый язык для будущего разработки приложений.
Swift покажется знакомым для разработчиков Objective-C. Он перенимает читаемость именованных параметров из Objective-C и силу его динамической объектной модели. Он предоставляет простой доступ к существующим фреймворкам Cocoa и возможность смешивать код с Objective-C кодом.
Основываясь на этой общей площадке, Swift предоставляет многие новые возможности и унифицирует процедурные и объектно-ориентированные части языка.
Swift дружественен к новым программистам. Это первый язык для разработки систем индустриального качества, который так же выразителен и прост, как скриптовый язык. Он поддерживает “песочницу” – инновационную функцию, позволяющую разработчикам экспериментировать с кодом и сразу видеть результат, без сборки и запуска приложения.
Swift совмещает лучшие идеи из современных языков с мудростью инженерной культуры Apple. Компилятор оптимизирован для производительности и язык оптимизирован для разработки – без компромиссов с той или другой стороны. Он разработан для приложений от “Hello, world” до масштабов целой операционной системы. Все это делает Swift солидным вкладом для разработчиков и для самой Apple.
Swift – это фантастический способ разработки iOS и OS X приложений и продолжит развиваться с новыми функциями и возможностями.
“У нас(Apple) амбициозные цели для Swift. И мы очень ждем ваших приложений, созданных с его помощью.”
Тур по Swift
Традиционно, рассказ о новом языке начинается с Hello, world!
В Swift это делается так:
println("Hello, world!")
Если вы писали код в C или Objective-C, этот синтаксис выглядит знакомым – в Swift, эта строка кода является завершенной программой. Не нужно импортировать библиотеку для работы с вводом/выводом или работой со строками. Код, написанный в глобальной области видимости (global scope), используется как входная точка для приложения, поэтому функция main() не нужна. Также не нужно ставить точки с запятой в конце каждого оператора.
В этом туре вы узнаете достаточно информации для того, чтобы начать писать код в Swift – мы решим ряд типичных задач. Не волнуйтесь, если что-то будет непонятно – все, о чем будет рассказано в этом туре, далее в книге будет объяснено еще более подробно.
Для лучшего результата, советуем открыть эту главу в песочнице (playground) XCode. Она позволит вам редактировать код и сразу видеть результат. Примечание переводчика – для запуска Playground, достаточно установить XCode 6, запустить и открыть пункт “Get started with a playground”.
Простые значения
Используйте let для создания констант и var для объявления переменных. Значение константы не обязательно должно быть известно на момент компиляции, но оно должно присваиваться строго один раз. Это значит, что вы можете использовать константу для обозначения значения, определяемого единажды, но используемого во многих местах.
var myVariable =42 myVariable =50 let myConstant =42
Константа или переменная должна иметь тот е тип, что и значение, которое вы хотите присвоить ей, однако вам не обязательно всегда объявлять тип – компилятор сам может определить тип, если при создании константы или переменной вы указываете ее значение. В приведенном выше примере, компилятор определит, что myVariable – это целое число (integer), т.к. начальное значение – целое число.
Если начальное значение не предоставляет достаточной информации (или его нет), укажите тип вручную:
let implicitInteger =70 let implicitDouble =70.0 let explicitDouble:Double=70
Попробуйте сами создать константу типа Float со значением 4.
Значения никогда не конвертируются в другой тип неявно. Если необходимо сконвертировать значение в другой тип, вы должны явно это показать:
let label ="The width is" let width =94 let widthLabel =label + String(width)
Попробуйте удалить конвертацию из String в последнией строке. Какую ошибку вы получите?
Есть еще более простой способ включить значения в строки:
let apples =3 let oranges =5 let appleSummary ="I have \(apples) apples." let fruitSummary ="U have \(apples + oranges) pieces of fruit."
Попробуйте использовать \() для включения дробных чисел в строку и для вставки чьего-нибудь имени в приветствие.
Массивы и словари создаются с помощью [], как и доступ к их элементу (по ключу или по индексу):
var shoppingList =["catfish","water","tulips","blue paint"] shoppingList[1]="bottle of water" var occupations =["Malcolm":"Captain","Kaylee":"Mechanic"] occupations["Jayne"]="Public relations"
Чтобы создать пустой массив или словарь, используйте синтаксис инициализации:
let emptyArray =String[]() let emptyDictionary =Dictionary<String,Float>()
Контроль управления
if и switch используются для условий, for-in, for, while, do-while – для циклов. Скобки вокруг условий опциональны. Фигурные скобки вокруг тела – обязательны.
let individualScores =[75,43,103,87,12] var teamScore =0 for score in individualScores { if score >50{ teamScore +=3} else{ teamScore +=1} } teamScore
В if выражение должно возвращать Boolean, поэтому код типа if score { … } – это ошибка, никакого неявного сравнения с нулем не будет.
Можно использовать if и let вместе для работы со значениями, которые могут отсутствовать – они представлены, как опциональные значения. Опциональное значение может содержать значение или nil для обозначения того, что значение отсутствует. Для создания “опционального значения” используется знак вопроса:
var optionalString:String?="Hello" optionalString ==nil var optionalName:String?="John Appleseed" var greeting ="Hello!" if let name = optionalName { greeting ="Hello, \(name)"}
Измените optionalName на nil. Какое приветствие вы получите? Добавьте else, отображающий другое приветствие для случаев, когда optionalName является nil.
Если опциональное значение равно nil, то условие вернет false и код будет пропущен. Иначе, опциональное значение будет присвоено константе и мы сможем использовать его внутри блока кода.
Switch поддерживает любой вид данных и широкое монжество операторов сравнения – он не ограничен одними лишь целыми числами и сравнениями на равенство:
let vegetable ="red pepper" switch vegetable { case"celery": let vegetableComment ="Add some raisins and make ants on a log." case"cucumber","watercress": let vegetableComment ="That would make a good tea sandwich." case let x where x.hasSuffix("pepper"): let vegetableComment ="Is it a spicy \(x)?" default: let vegetableComment ="everything tastes good in soup"}
Попробуйте убрать default случай. Какую ошибку вы получите?
После выполнения кода внутри switch-кейса, который совпал по условию, программа выходит из switch (а не продолжает идти по остальным свитчам, поэтому нет необходимости использовать break).
Можно использовать for-in для итерации по элементам в словаре, указав пару имен для каждого ключа-значения:
let interestingNumbers =["Prime":[2,3,5,7,11,13],"Fibonacci":[1,1,2,3,5,8],"Square":[1,4,9,16,25],] var largest =0 for (kind, numbers) in interestingNumbers { for number in numbers { if number > largest { largest = number } } } largest
Добавьте другую переменную для хранения информации о том, какого типа является самое большое число
While используется для повторения блока кода, пока не измениься условие. Можно перенести условие в конеч и использовать do-while:
var n =2 while n <100{ n = n *2} n var m =2 do{ m = m *2 }while m <100 m
Можно хранить индекс в цикле – или используя .. для создания диапазона индексов, или написав явную инициализацию, условие и инкремент.
Следующие два цикла делают одно и то же:
var firstForLoop =0 for i in 0..3{ firstForLoop +=1} firstForLoop var secondForLoop =0; for var i =0; i < 3; ++i { secondForLoop +=1} secondForLoop
Используйте .. для создания диапазона, не включающего верхнее значение (т.е. цикл идет для i = 0, 1, 2) и … для диапазона, включающего оба значения (т.е. for i in 0…3 – это i = 0, 1, 2, 3).
Функции и замыкания (closures)
Используйте func для объявления функции. Функция вызывается по ее имени и списку параметров в скобках. Используйте -> для отделения имен параметров и типов от возвращаемого значения функции:
func greet(name:String, day:String)->String{ return"Hello \(name), today is \(day)." } greet("Bob","Tuesday")
Удалите параметр day. Добавьте параметр для включения сегодняшнего особого блюда в приветствие.
Используйте кортеж (tuple) для возврата нескольких значений из функции:
func getGasPrices()->(Double,Double,Double){ return(3.59,3.69,3.79) } getGasPrices()
Функции могут использовать разное число аргументов, собирая их в массив:
func sumOf(numbers:Int...)->Int{ var sum =0 for number in numbers { sum += number } return sum } sumOf() sumOf(42,597,12)
Напишите функцию, которая считает среднее значение для ее аргументов
Функции могут быть вложенными. Вложенные функции имеют доступ к переменным, объявленным во внешнем функции. Используйте вложенные функции для организации кода длинной и сложной функции.
func returnFifteen()->Int{ var y =10 func add(){ y +=5 } add() return y } returnFifteen()
Функции по своей сути являются типом – то есть вы можете возвращать функцию из функции:
func makeIncrementer()->(Int->Int){ func addOne(number:Int)->Int{ return 1 + number } return addOne } var increment = makeIncrementer() increment(7)
Функция может принимать другую функцию, как ее аргумент:
func hasAnyMatches(list:Int[], condition:Int->Bool)->Bool{ for item in list { if condition(item){ return true } } return false } func lessThanTen(number:Int)->Bool{ return number <10 } var numbers =[20,19,7,12] hasAnyMatches(numbers, lessThanTen)
Функции – это на самом деле специальный случай замыканий. Вы можете написать замыкание без имени, окружив код фигурными скобками. Используйте in для разделения аргументов и типа возвращаемого значения от тела замыкания:
numbers.map({(number:Int)->Int in let result =3* number return result })
Перепишите замыкание так, чтобы оно возвращало 0 для всех нечетных номеров
У вас есть несколько опций для написания замыканий более кратко. Когда тип замыкания уже известен, например обратный вызов делегата (callback), вы можете пропустить тип его параметров, тип возвращаемого значения или и то и другое. Однострочное замыкание в примере ниже возвращает значение своего единственного выражения:
numbers.map({ number in 3 * number })
Вы можете ссылаться на параметры по номеру, вместо его имени – этот подход особенно удобен в очень коротких замыканиях.
Замыкание, переданное как последний аргумент для функции, может появляться сразу после скобок:
sort([1,5,3,12,2]){ $0 > $1 }
Объекты и классы
Используйте слово class с именем класса для создания класса.
Объявление свойства класса делается так же, как объявление обычной переменной или константы – с тем лишь исключением, что оно теперь находится в контексте класса. Аналогично, методы и функции задаются внутри класса:
class Shape{ var numberOfSides = 0 func simpleDescription()->String{ return "A shape with \(numberOfSides) sides." } }
Добавьте константное свойство с помощью let; добавьте метод, который принимает аргумент.
Создается объект из класса, используя скобки после имени класса. Используйте синтаксис с точкой для доступа к свойствам и методам объекта:
var shape =Shape() shape.numberOfSides =7 var shapeDescription = shape.simpleDescription()
Эта версия класса Shape не имеет одного важного свойства – инициализатора, который настроит объект при его создании.
Используем метод init для этого:
class NamedShape{ var numberOfSides:Int=0 var name:String init(name:String){ self.name = name } func simpleDescription()->String{ return "A shape with \(numberOfSides) sides." } }
Обратите внимание на то, что для доступа к своим свойствам класс использует self.
Аргументы инициализатору передаются так же, как при вызове функции:
var shape =NamedShape("My shape")
Каждое свойство должно иметь значение – заданное или при объявлении (как в случае numberOfSides), или в инициализаторе (как в случае name).
Используйте метод deinit для создания деинициализатора, если нужно перед уничтожением объекта выполнить какую-то очистку.
Классы могут наследоваться. Наследующие классы включают имя суперкласса (их родителя) после своего имени. При этом, классу не обязательно наследоваться от какого-то другого класса (в отличие от Objective-C, где нужно было наследоваться от NSObject – примечание переводчика), в этих случаях имя родителя можно пропустить.
Класс-наследник может определять методы своего родителя, используя слово override – в противном случае, компилятор сообщит об ошибке. Компилятор также определяет методы, которые помечены как override, но на самом деле ничего не переопределяют.
Проиллюстрируем все это с помощью кода:
class Square:NamedShape{ var sideLength:Double init(sideLength:Double, name:String){ self.sideLength = sideLength super.init(name: name) numberOfSides =4} func area()->Double{ return sideLength * sideLength } override func simpleDescription()->String{ return"A square with sides of length \(sidesLength)." } } let test =Square(sideLength:5.2, name:"my test square") test.area() test.simpleDescription()
Создайте другой подкласс NamedShape – например, Circle, который принимает в качестве параметров радиус и имя. Напишите метод area и describe для описания класса Circle
В дополнение к простым хранимым свойствам, свойства могут также иметь getter и setter методы, т.е. методы, используемые для получения и установки их значения.
Например:
class EquilateralTriangle:NamedShape{ var sideLength:Double=0.0 init(sideLength:Double, name:String){ self.sideLength = sideLength super.init(name: name) numberOfSides =3 } var perimeter:Double{ get{ return 3.0 * sideLength } set{ sideLength = newValue /3.0 } } override func simpleDescription()->String{ return "An equilateral triangle with sides of length \(sideLength)." } } var triangle =EquilateralTriangle(sideLength:3.1, name:"a triangle") triangle.perimeter triangle.perimeter =9.9 triangle.sideLength
В сеттере для свойства perimeter, newValue – это псевдоним для нового значения, которое передается. Можно предоставить другой псевдоним, указав его в скобках после set.
Обратите внимание, что инициализатор для EqualiateralTriangle имеет три разных шага:
- Устанавливает значение свойств, объявляемых подклассом
- Вызывает инициализатор класса-предка
- Изменяет значение свойств, объявленных предком.
Любые дополнитеьлные действия так же можно сделать на последнем шаге.
Если вам не нужно вычислять свойство, но по прежнему нужно предоставить код, который будет запущен до и после получения нового значения, используйте willSet и didSet. Например, класс ниже проверяет, что длина стороны треугольника всегда такая же, как длина стороны квадрата:
class TriangleAndSquare{ var triangle:EquilateralTriangle{ willSet { square.sideLength = newValue.sideLength } } var square:Square{ willSet { triangle.sideLength = newValue.sideLength } } init(size:Double, name:String){ square =Square(sideLength: size, name: name) triangle =EquilateralTriangle(sideLength: size, name: name) } } var triangleAndSquare =TriangleAndSquare(size:10, name:"another test shape") triangleAndSquare.square.sideLength triangleAndSquare.triangle.sideLength triangleAndSquare.square =Square(sideLength:50, name:"larger square") triangleAndSquare.triangle.sideLength
Методы в классах имеют одно важное отличие от функций. Имена параметров в функциях используются только внутри функции, но имена параметров в методах используются так же при вызове метода (кроме первого параметра). По умолчанию, метод имеет одно и то же имя параметра при вызове и внутри самого метода. Но можно указать второе имя, используемое в самом методе:
classCounter{ var count :Int=0 func incrementBy(amount:Int, numberOfTimes times:Int){ count += amount * times } } var counter =Counter() counter.incrementBy(2, numberOfTimes:7)
Работая с опциональными значениями, вы можете написать ? перед операциями типа методов, свойств и обращений к элементам массива или словаря. Если значение перед ? – nil, то все после ? игнорируется и значение всего выражения – nil. Иначе, опциональное значение используется для вычисления выражения. В обоих случаях, значение всего выражение также является опциональным значением:
let optionalSquare:Square?=Square(sideLength:2.5, name:"optional square") let sideLength = optionalSquare?.sideLength
Перечисления (enumerations) и структуры
enum используется для создания перечисления. Как классы и другие именованные типы, перечисления могут иметь ассоциированные с ними методы:
enum Rank:Int{ case Ace = 1 case Two,Three,Four,Five,Six,Seven,Eigth,Nine,Ten case Jack,Queen,King func simpleDescription()->String{ switch self{ case .Ace: return "ace" case .Jack: return"jack" case .Queen: return"queen" case .King: return"king" default: return String(self.toRaw()) } } } let ace =Rank.Ace let aceRawValue = ace.toRaw()
Напишите функцию, которая сравнивает два значения Rank, используя их “исходные” (toRaw()) значения
В примере выше, исходное значение перечисления имеет тип Int, поэтому мы указали только первое – Ace равное 1. Остальные были добавлены по очереди (2, 3, 4 и т.д.). Можно также использовать строки или дробные числа в качестве исходных значений перечисления.
Используйте toRaw и fromRaw для перехода от исходного значения к значению перечисления и обратно.
if let convertedRank =Rank.fromRaw(3){ let threeDescription =convertedRank.simpleDescription() }
Значения элементов перечисления – это настоящие значения, а не просто другой способ записи исходных значений. По сути, в случаях, где нет разумного исходного значения, его не обязательно подставлять:
enum Suit{ case Spades,Hearts,Diamonds,Clubs func simpleDescription()->String{ switch self{ case .Spades: return "spades" case .Hearts: return "hears" case .Diamonds: return"diamonds" case .Clubs: return"clubs" } } } let hearts =Suit.Hearts let heartsDescription = hearts.simpleDescription()
Добавьте метод color к Suit, который возвращает “black” для Spades и Clubs и “red” для hearts и diamonds
Обратите внимание на то, как мы используем Hearts в двух разных случаях: когда присваиваем значение константе hearts, мы используем полное имя Suit.Hearts, т.к. константа не имеет определенного типа. Внутри switch’a, мы используем .Hearts, т.к. находимся внутри self. Можно использовать эту сокращенную форму всегда, когда тип значения уже известен.
Используйте struct, чтобы создать структуру. Структуры поддерживают многое из поведения классов, включая методы и инициализаторы. Одно из самых важных отличий между структурами и классами заключается в том, что структуры всегда копируются, когда передаются внутри кода, а классы – всегда передаются по ссылке.
structCard{var rank:Rankvar suit:Suit func simpleDescription()->String{ return "The \(rank.simpleDescription()) of \(suit.simpleDescription())" } } let threeOfSpades =Card(rank:.Three, suit:.Spades) let threeOfSpadesDescription = threeOfSpades.simpleDescription()
Добавьте к Card метод, который создает полную колоду карт, с одной картой для каждой комбинации номера и рубашки
Объект перечисления может иметь значения, ассоциирующиеся с объектом. Объекты одного и того же члена перечисления могут иметь разные значения, ассоциированные с ними. Вы предоставляете ассоциированные значения, когда создаете объект. Ассоциированные значения и исходные значения различны: исходное значение члена перечисления одинаковы для всех его объектов, вы задаете его при определении перечисления. Например, рассмотрим случай запроса времени заката и рассвета с сервера. Сервер отвечает или информацией, или ошибкой.
enumServerResponse{ case Result(String,String) case Error(String) } let success =ServerResponse.Result("6:00 am","8:09 pm") let failure =ServerResponse.Error("Out of cheese.") switch success { case let.Result(sunrise, sunset): let serverResponse ="Sunrise is at \(sunrise) and sunset is at \(sunset)." case let.Error(error): let serverResponse ="Failure… \(error)" }
Добавьте третий случай для ServerResponse к switch’у
Обратите внимание, как время заката и рассвета достаются из ServerResponse как пара значений, соответствующих случаям case.
Протоколы и расширения
Используйте слово protocol для объявления протокола.
protocol ExampleProtocol{var simpleDescription:String{get} mutating fund adjust()}
Классы, перечисления и структуры могут соответствовать протоколам:
class SimpleClass:ExampleProtocol{ var simpleDescription:String="A very simple class." var anotherProperty:Int=66923 func adjust(){ simpleDescription +=" Now 100% adjusted." } } var a =SimpleClass() a.adjust() let aDescription = a.simpleDescription structSimpleStructure:ExampleProtocol{ var simpleDescription:String="A simple structure" mutating fund adjust(){ simpleDescription +=" (adjusted)" } } var b =SimpleStructure() b.adjust()let bDescription = b.simpleDescription
Напишите перечисление, которое будет отвечать этому протоколу
Обратите внимание на ключевое слово mutating, которое обозначает метод, модифицирующий структуру. Объявление класса не требует добавления слова mutating, т.к. методы класса всегда могут модифицировать класс.
Используйте слово extension (расширение) для добавления функциональности существующему типу, например новых методов или вычисленных свойств. Вы можете использовать расширение для добавления совместимости с протоколом типу, который объявлен в другом месте, или даже типу, который вы импортировали из библиотеки или фреймворка:
extension Int:ExampleProtocol{ var simpleDescription:String{ return "The number \(self)" } mutating func adjust(){ self+=42 } } simpleDescription
Напишите расширение для типа Double, которое добавляет свойство absoluteValue
Вы можете использовать имя протокола, как любой другой именованный тип – например, создать коллекцию объектов, которые имеют разные типы, но все соответствуют одному протоколу. Когда вы работаете со значениями, тип которых – протокол, методы вне объявления протокола недоступны.
let protocolValue:ExampleProtocol= a protocolValue.simpleDescription // protocolValue.anotherProperty // раскомментируйте и посмотрите на ошибку
Хотя переменная protocolValue будет иметь тип SimpleClass во время исполнения, компилятор работает с ней как с переменной типа ExampleProtocol – это значит, что вы не сможете случайно обратиться к методам или свойствам, которые класс реализует в дополнение к протоколу.
Общие функции и типы
Напишите имя внутри <>, чтобы создать общую функцию или тип:
func repeat<ItemType>(item :ItemType, times:Int)->ItemType[]{ var result =ItemType[]() for i in 0..times { result += item } return result } repeat("knock",4)
Вы можете создать общие формы функций и методов, так же как и классов, перечислений и структур.
// Переопределяем опциональный тип из стандартной библиотеки Swift: enumOptionalValue<T>{ caseNonecaseSome(T) } var possibleInteger:OptionalValue<Int> =.None possibleInteger =.Some(100)
Используйте where после имени типа, чтобы указать список требований – например, потребовать, чтобы тип реализовывал протокол, потребовать чтобы два типа были одинаковы или потребовать, чтобы класс имел определенный суперкласс:
func anyCommonElements <T, U where T:Sequence, U:Sequence, T.GeneratorType.Element:Equatable, T.GeneratorType.Element== U.GeneratorType.Element>(lhs: t, rhs: U)->Bool{ for lhsItem in lhs { for rhsItem in rhs { if lhsItem == rhsItem {return true} } } return false } anyCommonElements([1,2,3],[3])
Модифицируйте anyCommonElements, чтобы сделать функцию, возвращающую массив элементов, общих для обоих последовательностей
В простых случаях, where можно пропустить и просто написать имя класса или протокола после двоеточия. Т.е. написать <T: Equatable> – это то же самое, что и <T where T: Equatable>.
Основы
Swift – новый язык программирования для создания iOS и OS X приложений. Однако, многие части Swift могут быть вам знакомы из опыта разработки на С и Objectve-C.
Swift предоставляет свои собственные версии всех фундаментальных типов С и Objective-C, включая Int для целых, Double и Float для чисел с плавающей запятой, Bool для логических значений и String для текстовых данных. Swift также предоставляет мощные версии двух основных типов коллекций – Array (массив) и Dictionary (словарь), это описано в типах коллекций.
Как С, Swift использует переменные для хранения и ссылки на значения, используя имя. Swift также широко использует переменные, чьи значения не могут быть изменены. Они известны как константы, и они гораздо более мощные, чем константы в Си. Константы используются в Swift для того, чтобы сделать код безопаснее и чище в случаях, когда вы работаете со значениями, которые не должны меняться.
В дополнение к известным типам, Swift добавляет новые типы, которых нет в Objective-C. Они включают в себя кортежи (tuple), которые позволяют создавать и передавать группы значений. Кортежи могут возвращать множество значений из функции как одно составное значение.
Swift также добавляет опциональные типы, которые позволяют работать с отсутствием значения. Опциональные типы говорят или “у меня есть значение и оно равно х”, или “у меня вообще нет значения”. Опциональные значения схожи в использовании с nil и указателями в Objective C, но они работают для любого типа данных, а не только для классов. Опциональные значения безопаснее и выразительнее, чем nil-указатели в Objective-C и часто используются во многих мощных функциях Swift.
Опциональные типы – это пример того факта, что Swift является языком с типовой безопасностью (type safe). Swift помогает вашему коду быть ясным о типах значений, с которыми он работает. Если часть вашего кода ожидает строку, типовая безопасность предотвращает вас от передачи туда целого числа по ошибке. Это позволяет вам ловить и исправлять ошибки как можно раньше в процессе разработки.
Константы и переменные
Константы и переменные ассоциируют имя (например, maximumNumberOfLoginAttempts или welcomeMessage) со значением определенного типа (например, число 10 или строка “Hello”). Значение константы не может быть изменено после того, как было задано, тогда как переменная может быть изменена на другое значение в будущем.
Объявление констант и переменных
Константы и переменные должны быть объявлены, прежде чем они будут использованы. Константы объявляются с помощью ключевого слова let, переменные – слова var. Вот пример того, как константы и переменные могут быть использованы для отслеживания количества попыток логина, предпринятого пользователем:
let maximumNumberOfLoginAttempts =10 var currentLoginAttempt =0
Код можно прочитать как “объявите новую константу, названную maximumNumberOfLoginAttempts, и задайте ей значение 10. Затем объявите новую переменую, названную currentLoginAttempt, и дайте ей начальное значение 0.”
В этом примере, максимальное количество разрешенных попыток входа объявляется константой, т.к. оно никогда не меняется. Текущее количество попыток объявляется как переменная, т.к. это значение должно увеличиваться после каждой неудачной попытки.
Вы можете объявить несколько констант или несколько переменных на одной строке, разделив их запятой:
var x =0.0, y =0.0, z =0.0
Если значение, которое вы храните, не будет меняться – всегда объявляйте его как константу, используя слово let. Используйте переменные только для хранения значений, которые должны меняться.
Аннотации(обозначения) типов
Вы можете добавить аннотацию типа, когда объявляете константу или переменную, чтобы точно обозначить тип значений, которые она может хранить. Аннотация типа отделяется двоеточием от названия переменной или константы. Приведем пример:
var welcomeMessage:String
Эту строку можно прочитать как “Объявите переменную, названную welcomeMessage, чтобы она хранила текстовые (String) значения”. Таким образом, мы показываем, какие именно значения будет содержать переменная (в данном случае – текст/строку).
Переменной welcomeMessage теперь можно присовить любое строковое значение, и это не вызовет ошибок:
welcomeMessage ="Hello"
На практике, обозначения типов придется писать редко. Если вы предоставите начальное знаение для переменной или константы, Swift почти всегда сможет сам распознать тип значений, которые она должна содержать. Это будет описано в разделе “Безопасность типов и подбор типов”. В примере с welcomeMessage, мы не предоставили начального значения, поэтому мы указываем тип явно.
Имена для констант и переменных
Вы можете использовать практически любые символы для названий констант и переменных, включая символы юникода:
let ?=3.14159 let ??="????"
Имена констант и переменных не могут содержать математических символов, стрелок, точек и некоторых символов Unicode (private-use or invalid Unicode code points), символов для рисования линий или прямоугольников. Они так же не могут начинаться с цифры, хотя в целом цифры можно использовать в любой другой части имени.
Как только вы объявили константу или переменную определенного типа, вы не можете переопределить ее снова с тем же именем или поменять тип хранимых данных. Вы так же не можете превратить константу в переменную или наоборот.
Если вам необходимо дать переменной или константе название, которое является ключевым словом в Swift, вы можете сделать это, окружив это слово символами “, однако этого следует избегать.
Вы можете поменять значение существующей переменной на другое значение того же типа. Например, поменяем friendlyWelcome с "Hello!" на "Bonjour!":
var friendlyWelcome ="Hello!" friendlyWelcome ="Bonjour!"// friendlyWelcome теперь содержит "Bonjour!"
В отличие от переменной, значение константы нельзя поменять после установки – в противном случае, компилятор выдаст ошибку:
let languageName ="Swift" languageName ="Swift++"// тут мы получим ошибку, т.к. нельзя менять значение константы
Вывод значений констант и переменных на экран
Вы можете вывести текущее значение константы или переменной, используя функцию println:
println(friendlyWelcome)// получим на экране Bonjour!
println – это глобальная функция, которая выводит на экран значение, после чего делает переход на новую строку. Если вы работаете в XCode, к примеру, то это сообщение будет выведено в окошке “console” (консоль). Есть другая функция – print – она делает то же самое, что и println, но не переводит текст на новую строку
Вы можете напечатать с помощью println любую строку:
println("This is a string")
Функция println может печатать и более сложные сообщения, как и функция NSLog в Cocoa (знакомая для разработчиков Objective-C). Эти сообщения могут включать значения констант и переменных.
Swift использует интерполяцию строк для включения имени константы или переменной в определенное место строки – для этого, она должна быть заключена в скобки и предваряться обратным слэшем, вот так:
println("The current value of friendlyWelcome is \(friendlyWelcome)")// печатает The current value of friendlyWelcome is Bonjour!
Об остальных возможностях строкой интерполяции читайте в разделе “Интерполяция строк” на нашем сайте
Комментарии
Используйте комментарии, чтобы включить неисполняемый текст в ваш код, в качестве пометки или напоминания для себя. Компилятор игнорирует их при компиляции приложения.
Комментарии в Swift аналогичны комментариям в С. Однострочные комментарии начинаются с двух слэшей:
// это комментарий
Вы можете написать многострочный комментарий, начав его с символов /* и закончив */:
/* это тоже комментарий,
но он на нескольких строках */
В отличие от многострочных комментариев в С, многострочные комментарии в Swift могут быть вложенными:
/* начало комментария /* а вот мы вложили комментарий и закончили это вложение */ и закрыли первый комментарий*/
Вложенные комментарии позволяют вам закомментировать большие куски кода быстро и без проблем, даже если он уже содержит многострочные комментарии.
Точка с запятой
В отличие от многих других языков, Swift не требует от вас писать точку с запятой после каждой строчки кода, но вы можете писать их, если захотите. Точки с запятой обязательны, однако, если вы хотите написать несколько утверждений в одной строке:
let cat ="cat"; println(cat);//печатает cat
Целые числа (тип Integer)
Целые числа (Integer) – это числа, не содержащие дробной части, например 42 или -23. Они так же могут быть знаковыми (положительными, отрицательными или нулем) или беззнаковыми (положительным или нулем).
Swift представляет целые числа в виде знаковых и беззнаковых целых с размерами в 8, 16, 32 и 64 бита. Эти целые числа следуют стандартному именованию в Си, то есть 8битное беззнаковое целое число имеет тип UInt8, 32битное знаковое число – Int32. Как и все типы в Swift, эти типы целых чисел должны начинаться с большой буквы.
Границы целых чисел
Вы можете получить минимальное и максимальное значение каждого числа с помощью свойств min и max:
let minValue =UInt8.min // минимальное значение равно 0 для этого типа let maxValue =UInt8.max // максимальное значение равно 255 для этого типа
Значения этих свойств (0 и 255 в нашем случае) имеют тип самого свойства (UInt8 в нашем случае), соответственно minValue и maxValue автоматом становятся типа UInt8.
Int
В большинстве случаев, вам не придется выбирать специальный размер целого числа для использования в вашем коде – в Swift есть тип Int, который имеет тот же размер, что и “родной” размер слова для текущей платформы, а именно:
- для 32битных платформ – Int имеет тот же размер, что и Int32
- для 64битных платформ – Int имеет тот же размер, что и Int64
Если вам не нужно работать с особым размеров целых чисел, используйте Int для целых чисел в вашем коде – это позволяет коду быть последовательным и совместимым. Даже на 32 битных платформах, Int может хранить любое значение от -2 147 483 648 до 2 147 483 647 – что является достаточно большим для большинства задач.
UInt
Swift также предоставляет беззнаковый тип целых чисел UInt, который имеет тот же размер, что и “родной” размер слова на текущей платформе:
- для 32битных платформ – UInt имеет тот же размер, что и UInt32
- для 64битных платформ – UInt имеет тот же размер, что и UInt64
Используйте UInt только когда вам действительно нужен беззнаковый целый тип размером со слово (word) платформы. В других случаях, предпочтительнее использовать Int, даже если известно, что значения будут неотрицательными. Последовательное использование Int для целых чисел позволяет содержать код совместимым, избегает нужды в конвертации между разными типаци чисел и соответствует определению целого типа, как описано в разделе “Безопасность типов и подбор типов” на нашем сайте.
Числа с плавающей точкой
Числа с плавающей точкой – это числа, у которых есть дробная часть, например 3.14159, 0.1 и -273.15.
Числа с плавающей точкой могут представлять гораздо более широкий диапазон значений, чем целые числа, а также хранить числа, которе гораздо больше или меньше, чем те, что хранятся в Int. В Swift есть два типа чисел с плавающей точкой:
- Double является 64битным числом с плавающей точкой – его следует использовать, когда значения должны быть очень большими или особенно точными
- Float является 32битным числом с плавающей точкой – используйте во всех остальных случаях, когда высокая точность не требуется
Double имеет точность в минимум 15 десятичных знаков, тогда как Float – только 6. Подходящий для использования тип зависит от природы и диапазона значений, с которыми вам требуется работать.
Безопасность типов и подбор(inference) типов
Swift является языком с типовой безопасностью. Типовая безопасность позволяет вам быть точным о типах значений, с которыми работает ваш код. Если кусок кода ожидает строковый тип, вы не сможете по ошибке передать туда число.
Поскольку Swift безопасен, он выполняет проверки типов при компиляции кода и помечает любые несоответствующие типы как ошибки, что позволяет вам ловить их максимально рано при разработке.
Проверка типов позволяет вам избежать ошибок, когда вы работаете с разными типами значений. Однако, это не означает, что вам обязательно объявлять тип каждой константы или переменной – если вы не объявите тип сами, Swift использует подбор(inference) типа для определения подходящего типа. Интерфейс типа позволяет компилятору делать вывод о типе по операциям в вашем коде во время компиляции.
Из-за подбора типа, Swift требует гораздо меньше объявлений, чем языки типа С или Objective-C. Константы и переменные по прежнему явно типизированы, но большинство работы по определению типа сделано за вас.
Подбор типа особенно полезен, когда вы объявляете константу или переменную с начальным значением – это часто делается с помощью присвоения литерального значения (литерала) константе или переменной в момент ее объявления. Литерал – это просто значение, которое появляется в вашем коде, например 42 или 3.14159.
Например, если вы присваиваете литерал 42 новой константе без объявления ее типа, Swift автоматически догадывается, что тип вашей константы – Int, поскольку вы инициализируете ее числом, похожим на целое число:
let meaningOfLife =42// meaningOfLife автоматически становится Int
Точно так же, если вы не указываете тип для литерала с плавающей точкой, Swift предположит, что вы хотите использовать тип Double:
let pi =3.14159// pi имеет тип Double
Swift всегда выбирает Double, а не Float, если вы не указываете тип явно.
Если вы совместите в одной строке целочисленный литерал и литерал с плавающей точкой, тип будет также Double:
let anotherPi =3+0.14159// anotherPi - также Double
Литеральное значение 3 не имеет заданного типа, зато компилятор видит присутствие плавающей точки – поэтому и назначает тип Double.
Числовые литералы
Целоисленные литералы могут быть записаны как:
- Десятичное число без префикса
- Двоичное число с префиксом 0b
- Восьмеричное число с префиксом 0o
- Шестнадцатеричное число с префиксом 0x
Запишем число 17 каждым из способов:
let decimalInteger =17 let binaryInteger =0b10001// 17 в двоичном представлении let octalInteger =0o21// 17 в восьмеричном представлении let hexadecimalInteger =0x11// 17 в шестнадцатеричном представлении
Литералы с плавающей точкой могут быть десятичными (без префикса) или шестнадцатеричными (с префиксом 0x). Они обязаны всгеда иметь число (десятичное или шестнадцатеричное) с обеих сторон от точки. Они также могут иметь экспоненту, отделяемую от числа буквой e или E для десятичных и буквой p или P для шестнадцатеричных чисел.
Для десятичных чисел с экспонентой exp, базовое число умножается на 10exp:
- 1.25e2 означает 1.25 X 102, или 125.0
- 1.25e-2 означает 1.25 X 10-2, или 0.0125
Для шестнадцатеричных чисел с экспонентой exp, базовое число умножается на 2exp:
- 0xFp2 означает 15 X 22, или 60.0
- 0xFp-2 означает 15 X 2-2, или 3.72
Все следующие литералы с плавающей точкой имеют десятичное значение 12.1875:
let decimalDouble =12.1875 let exponentDouble =1.21875e1 let hexadecimalDouble =0xC.3p0
числовые литералы могут содержать дополнительное форматирование, чтобы их было легче читать. Как целые числа, так и числа с плавающей запятой могут быть дополнены нулями и содержать подчеркивания для повышения читаемости. Примеры:
let paddedDouble =000.123.456 let oneMillion =1_000_000 let justOVerOneMillion =1_000_000.000_000_1
Конвертация числовых типов
Используйте тип Int для всех своих целочисленных констант и переменных, даже если известно, что они будут неотрицательными (разумеется, за исключением особых случаев). Использование стандартного целого типа в повседневных ситуациях означает, что целочисленные константы и переменные сразу могут взаимодействовать с автоподставляемым типом для целочисленных литеральных значений. (от переводчика – вообще, здесь говорится о том, что переменные становятся interoperable – в данном случае, имеется ввиду, что все наши константы и переменные, если они будут иметь тип Int, общепринятый в системе – смогут безопасно работать со всеми другими константами и переменными, зная, что они тоже Int).
Используйте другие целочисленные типы только в тех ситуациях, когда они действительно нужны для конкретной задачи, например когда используются данные с заданным размером из внешнего источника, или для производительности, уменьшения использования памяти или других оптимизаций. Использование типов с явно заданным размером в таких ситуациях позволяет поймат любые случайные переполнения данных и явно документирует природу используемых данных/значений.
Конвертация целых чисел
Диапазон чисел, которые можно хранить в целочисленной константе или переменной, отличается для каждого типа – например, в Int8 можно хранить числа от -128 до 127, тогда как в UInt8 – числа от 0 до 255. Число, которое не помещается в диапазон приемлемых чисел, вызовет ошибку на этапе компиляции, например:
let cannotBeNegative:UInt8=-1// UInt8 не может хранить отрицательных значений, тут будет ошибка let tooBig:Int8=Int8.max +1// Int8 не может хранить число большее, чем максимальное значение, тут тоже ошибка
Поскольку каждый числовой тип может хранить разные диапазоны значений, вам в определенных случаях придется обращаться к явной конвертации числовых типов. Этот подход предотвращает от скрытых ошибок конвертации и позволяет ей быть явной в вашем коде.
Чтобы сконвертировать один числовой тип в другой, вам необходимо инициализировать новое число желаемого типа с использованием существующего значение. В примере ниже, константа twoThousand имеет тип UInt16, тогда как константа one имеет тип UInt8. Их нельзя напрямую добавлять друг к другу, поскольку они не одного типа. Вместо этого, мы вызываем UInt16(one), чтобы создать новое значение типа UInt16, используя значение константы one:
let twoThousand:UInt16=2_000 let one:UInt8=1 let twoThousandAndOne = twoThousand +UInt16(one)
Поскольку оба складываемых значения в последней строчке кода имеют тип UInt16, компилятор позволяет выполнить сложение – и выходная константа twoThousandAndOne будет иметь тип UInt16 – поскольку компилятор видит, что ей присваивается значение суммы двух UInt16-констант.
SomeType(ofInitialValue) (т.е. выражение вида НазваниеТипа(начальноеЗначение) – прим. переводчика) – это стандартный способ вызвать инциализатор типа в Swift и передать начальное значение. У типа UInt16 есть инициализатор, принимающий значение UInt8, и этот инициализатор используется, чтобы создать новый UInt16 из существующего UInt8. Однако, любой тип передать не получится – только тот тип, для которого UInt16 имеет соответствующий инициализатор. Впрочем, можно использовать расширения для создания своих инициализаторов – об этом будет рассказано в главе “Расширения” на нашем сайте.
Конвертация целых чисел и чисел с плавающей точкой
Конвертация между целыми числами и числами с плавающей запятой должна быть явной:
let three =3 let pointOneFourOneFiveNine =0.14519 let pi =Double(three)+ pointOneFourOneFiveNine // pi равно 3.14519 и он имеет автоматически определенный тип Double
Здесь, константа 3 используется для создания нового значения Double, таким образом в последней строке оба слагаемых имеют один тип. Без этой конвертации, сложение было бы невозможно (компилятор выдал бы ошибку).
Обратная конвертация также возможна, т.е. целочисленное значение можно инициализировать значением с плавающей точкой:
let integerPi =Int(pi)// integerPi равен 3, имеет тип Int
Для дробных значений, при конвертации в целое, просто отбрасывается дробная часть – т.е. 4.75 станет 4, -3.9 станет -3.
Правила для совмещения числовых констант и переменных отличаются от правил для числовый литералов. Литеральное значение 3 может быть добавлено напрямую к литеральному значению 0.14159, т.к. числовые литералы не имеют определенного типа – их тип определяется лишь когда они оцениваются компилятором.
Алиасы типов
Алиасы типов – это альтернативные имена для существующих типов. Их можно определить с помощью ключевого слова typealias.
Они очень полезны, когда вы хотите ссылаться на определенный тип названием, более подходящим в данном контексте. К примеру, вы работаете с данными определенного размера из внешнего источника:
typealias AudioSample=UInt16
Как только вы объявили алиас типа, вы можете испоьзовать его в любом месте, где вы использовали бы настоящее имя типа:
var maxAmplitudeFound =AudioSample.min //maxAmplitudeFound теперь 0
В данном примере, мы объявили AudioSample как алиас для UInt16 и, поскольку это алиас, мы можем обращаться к AudioSample.min, который на самом деле вызывает UInt16.min, предоставляющий, в свою очередь, значение для нашей переменной.
Логический тип (boolean)
Swift имеет базовый логический тип, называемый Bool. Логический тип (он же – булевый тип) называется так, поскольку он может содержать только два зачения – true(правда) или false(ложь). Swift предоставляет две соответствующие константы – true и false:
let orangesAreOrange =true let turnipsAreDelicious =false
Типы этих переменных – Bool, поскольку они инициализируются булевыми литеральными значениями, поэтому мы не объявляли их тип явно – это позволяет коду быть более читаемым.
Логические значения особенно полезны при работе с условными выражениями, например if:
if turnipsAreDelicious { println("ммм, вкусная репа!")} else{ println("фуу, репа ужасна!")}// напечатает "репа ужасна" (а лично я люблю репу! - прим. переводчика)
Условные выражения, такие как if, будут рассмотрены в главе “Управление контролем”.
Типовая безопасность языка предотвращает использование не-логических значений в выражениях, требующих логическое значение. Следующий пример (нормально компилирующийся в С и ObjectiveC), в Swift вызовет ошибку:
let i =1 if i {//тут будет ошибка}
Однако, альтернативный вариант будет корректным:
let i =1 if i == 1 {//тут все ок}
Результат сравнения i == 1 является логическим значением, поэтому второй пример проходит проверку типов. Сравнения описываются в следующей главе “базовые операторы”.
Как и в других примерах типовой безопасности Swift’a, этот подход избегает случайных ошибок и позволяет убедиться, что намерения каждой части кода всегда ясны.
Кортежи (tuples)
Кортежи (tuples) группируют несколько значений в одно составное значение. Это значение внутри кортежа может иметь любой тип и значениям не обязательно всем быть одного типа.
В следующем примере, (404, “Not found”) – это кортеж, который описывает код ответа HTTP. Код ответа HTTP – это специальное значение, которое веб-сервер возвращает вам каждый раз, когда вы запрашиваете веб-страницу. Код 404 Not found значит, что запрашиваемая страница не найдена.
let http404Error =(404,"Not found")// http404Error имеет тип (Int, String) и равен (404, "Not found")
Кортеж (404, “Not found”) группирует Int и String для того, чтобы вернуть код ответа HTTP, состоящего из двух частей – номера и понятного человеку описания. Мы можем описать этот тип как “кортеж типа (Int, String)”.
Вы можете создавать кортежи из любой перестановки типов и они могут содержать сколько угодно нужных вам типов. Можно создать кортежи (Int, Int, Int) или (String, Bool), в общем – любой, какой вам нужно.
Вы можете разобрать (или декомпозировать, или разложить – decompose) компоненты кортежа в отдельные константы или переменные, чтобы использовать их:
let(statusCode, statusMessage)= http404Error println("Код статуса \(statusCode)")// печатает "Код статуса 404" println("Сообщение - \(statusMessage)")// печатает "Сообщене - Not found"
Если вам нужны лишь некоторые из значений кортежа, можно игнорировать его части, используя подчеркивание (_) при разложении кортежа:
let(justTheStatusCode, _)= http404Error println("Код статуса \(justTheStatusCode)")// печатает "Код статуса 404"
Другой возможный вариант – доступ по индексу элемента, начиная от 0:
println("Код статуса \(http404Error.0)")// печатает "Код статуса 404" println("Сообщение - \(http404Error.1)")// печатает "Сообщене - Not found"
Можно также дать индивидуальные имена элементам в кортеже при его объявлении:
let http200Status =(statusCode:200, description:"OK")
Если вы дали имена элементам в кортеже, вы можете использовать их, чтобы обращаться к этим элементам:
println("Код статуса \(http200Status.statusCode)")// печатает "Код статуса 200" println("Сообщение - \(hhttp200Status.description)")// печатает "Сообщене - OK"
Кортежи особенно полезны, когда мы возвращаем значение из функций. ФФункция, которая скачивает веб страницу, может возвращать кортеж (Int, String) для обозначение успешности или неудачи совершенной операции. Возвращая кортеж с двумя значениями, каждое разного типа, функция предоставляет больше полезной информации о ее выполнении, чем если бы она возвращала какое-то одно значение. Для большей информации по теме, смотрите раздел “Функции с несколькими возвращемыми значениями” на нашем сайте.
Кортежи полезны для временных групп схожих значений. Они не предназначены для создания сложных структур данных. Если есть шанс, что ваши данные будут храниться в приложении некоторое время, лучше смоделировать их с помощью класса или структуры. Для большей информации на эту тему, почитайте раздел “Классы и структуры”.
Опциональные значения
Вы можете использовать опциональные знаения в ситуациях, где значение может отсутствовать. Опциональное значение говорит одно из двух:
- или “у меня есть значение и оно равно х”
- или ” у меня нет никакого значения”
Концепции опциональных значений не существует в С или Objective-C. Самое ближайшее в Objective-C – это возможность возвращать nil из метода, который возвращает объекты. nil как бы обозначает, что “корректный объект отсутствует”, однако это работает только объектов, но не для структур, базовых типов или перечислений. Для этих типов, Objective-C методы обычно возвращают какое-нибудь специальное значение (например, NSNotFound), чтобы обозначить отсутствие значения. Этот подход предполагает, что код, вызывающий метод, знает о том, что есть это специальное значение и что его нужно учитывать. ОПциональные значения в Swift позволяют вам указать возможность отсутствия значения для любого типа, без надобности использования дополнительных констант.
Приведем пример. Тип String имеет метод toInt, который пробует перевести содержимое строки в целочисленное значение типа Int. Однако, не каждая строка может быть сконвертирована вв целое число. Из строки “123” получается число 123, однако из строки “hello, world” нельзя получить целочисленного значения.
Пример ниже использует метод toInt, чтобы попробовать перевести строку в Int:
let possibleNumber ="123" let convertedNumber = possibleNumber.toInt()// convertedNumber теперь имеет тип "Int?" (да-да, именно Int со знаком вопроса), или так называемый "опциональный Int"
Поскольку метод toInt может не сработать, он возвращает опциональный Int, а не обычный Int. Опциональный Int записывается как Int? – знак вопроса показывает, что значение является опциональным, т.е. переменная или константа типа Int? может или содержать какое-либо значение Int?, или не содержать никакого значения вообще. (Она не может содержать ничего другого, т.е. Bool, String и т.д. _не_ могут храниться в ней. Либо Int, либо ничего).
Условные выражения и вынужденная распаковка (forced unwrapping)
Вы можете использовать if, чтобы выяснить, содержит ли опциональное значение какое-либо значение. Если оно содержит, то оно вернет true, иначе – false.
Как только вы убедились, что опциональное значение содержит значение, вы можете обратиться к нему, используя восклицательный знак в конце имени. Он обозначает ” я знаю, что это опциональное значение определенно содержит значение – пожалуйста, используйте его”. Это и называется “вынужденная распаковка” (мы как бы принуждаем компилятор “распаковать” значение – прим. переводчика).
if convertedNumber { println("\(possibleNumber) имеет целочисленное значение \(convertedNumber!)")} else{ println("\(possibleNumber) не может быть сконвертирован в целое число")}// печатает на экран "123 имеет целочисленное значение 123"
Для большей информации об условных конструкциях, обратитесь к главе “Контроль управления” на нашем сайте.
Попытка использовать ! для того, чтобы достать значение в случаях, когда его нет в опциональном значении, вызовет ошибку времени исполнения (runtime error), т.е. ошибку во время работы приложения. Поэтому всегда убеждайтесь, что значение содержится, прежде чем использовать восклицательный знак.
Опциональная связка
Вы можете использовать опциональную связку, чтобы узнать, содержит ли опциональная переменная значение и если содержит, то сохранить его во временную константу или переменную. Опциональная связка может быть использована с if и while, чтобы проверить, что значение присутствует в опциональной переменной и извлечь его в константу или другую переменную одним действием. if и while описываются в разделе “Контроль управления” на нашем сайте.
Опциональные связки реализуются следующим образом:
if let constantName = someOptional {// если _название константы_ = _некоторая опциональная переменная_// код}// то есть если в опциональной переменной someOptional есть значение, оно пишется в constantName и код внутри if выполняется
Наш предыдущий пример с конвертацией числа можно переписать следующим образом:
if let actualNumber = possibleNumber.toInt(){ println("\(possibleNumber) имеет целочисленное значение \(actualNumber)")} else{ println("\(possibleNumber) не может быть сконвертирован в целое число")}// печатает на экран "123 имеет целочисленное значение 123"
Этот код можно прочитать так:
“Если опциональный Int, возвращаемый методом possibleNumber.toInt, содержит значение, то создайте новую константу actualNumber со значением, которое там содержится”.
Если конвертация прошла успешно, actualNumber становится доступной в пределах первой ветки выражения if. Она уже инициализирована значением, поэтому нет нужды использовать восклицательный знак. В нашем примере мы просто выводим ее на экран.
Вы можете использовать как константы, так и переменные, для опциональной связки. Если вы хотите управлять значением actualNumber внутри вашего if, используйте var вместо let для объявления переменной, а не константы.
nil
Вы можете присвоить опциональной переменной состояние “без значения”, присвоив ей специальное значение nil:
var serverResponseCode:Int?=404//serverResponseCode содержит Int со значением 404 serverResponseCode =nil//serverResponseCode теперь не содержит значения
nil не может быть использован с не-опциональными константами и переменными. Если константа или переменная в вашем коде должна работать с отсутствием значений при определенных обстоятельствах, всегда определяйте ее как опциональную с подходящим типом.
Если вы определите опциональную константу или переменную, не предоставив значения, она автоматически получит nil (отсутствие значения):
var surveyAnswer:String?// surveyAnswer автоматически является nil
В Swift nil – не то же самое, что nil в Objective C. Там nil является указателем на несуществующий объект, в Свифте же – это не указатель, а отсутствие значения определенного типа. Опциональные переменные/константы любого типа могут быть установлены в nil, а не только объекты.
Неявное развернутые опциональные значения (implicit unwrapped optionals)
Как описано выше, опциональные значения обозначают, что константа или переменная может не иметь никакого значения. Мы можем проверить это, используя if и получить значение, используя восклицательный знак или опциональную связку.
Иногда из структуры приложения видно, что опциональная переменная или константа будет всегда иметь значение после того, как оно впервые было установлено. В этих слчаях, полезно каким-то образом убрать нужду в проверке и “доставании” значения каждый раз, когда мы обращаемся к этой переменной.
Такие опциональные переменные определяются как “неявно развернутые”. Вы можете объявить неявно развернутую опциональную переменную, поставив восклицательный знак вместо вопросительного при объявлении типа.
НЕявно развернутые опциональные константы и переменные полезны, когда известно, что значение будет постоянно присутствовать в переменной или константе с какого-то момента. Основное использование таких опциональных переменных в Swift – при инициализации класса, как описывается в разделе “Ссылки без владельцев и неявно развернутые опциональные свойства” (позже вставим сюда ссылку, когда переведем).
Неявно развернутая опциональная константа или переменная – это обычная опциональная переменная в своей сути, но может быть использована как неопциональная, без необходимости “доставать” ее значение при каждом доступе. Лучше всего посмотреть на этот ад на примере:
let possibleString:String?="Опциональная строка" println(possibleString!)// необходимо использовать восклицательный знак, чтобы получить доступ к значению// получим на экране "Опциональная строка" let assumedString:String!="Неявно развернутая опциональная строка" println(assumedString)// не требуется восклицательного знака для доступа// получаем на экране "Неявно развернутая опциональная строка"
Для удобства, можно считать, что неявно развернутая опциональная переменная или константа – это обычная опциональная переменная/константа, которой дано разрешения показывать свое значение автоматически, когда она используется. Вместо того, чтобы помещать восклицательный знак после опциональной переменной при каждом использовании, просто поместите восклицательный знак после названия типа при объявлении.
При попытке доступа к неявно развернутой опциональной переменной, когда она еще не получила значение, вы получите ошибку времени исполнения (runtime error). То же самое произойдет, если вы примените восклицательный знак к обычной опциональной переменной, которая не содержит значения.
Вы по-прежнему можете обращаться с неявно развернутой опциональной переменной как с обычной опциональной переменной, например для проверки на значение:
if assumedString { println(assumedString)}// выводим на экран "Неявно развернутая опциональная строка"
Вы также можете использовать ее с опциональной связкой для проверки и разворачивания значения в одной строке:
if let definiteString = assumedString { println(definiteString)}// выводим на экран "Неявно развернутая опциональная строка"
НЕявно развернутая опциональная строка не должна использоваться в случаях, когда есть шанс, что переменная не будет содержать значения (будет nil) в какой-то момент времени. Всегда используйте обычный опциональный тип в случаях, если нужно проверять на nil в течении жизненного цикла переменной.
Утверждения (они же ассерты, они же assertions)
Опциональные типы позволяют проверять значения, которые могут существовать или отсутствовать, и писать код, который красиво обрабатывает отсутствие значения. Однако, в некоторых случаях код не может продолжить выполнение в случае, когда значение не существует или не удовлетворяет определенным условиям. В этих ситуациях, вы можете вызвать ассерт (trigger an assertion) – это остановит выполнение кода и дасть возможность провести отладку, чтобы выяснить, откуда взялось неподходящее значение.
Отладка с утверждениями
Утверждение – это проверка, проходящая во время исполнения, которая убеждается, что определенное логическое условие является правдой (true). Оно в буквальном смысле “утверждает”, что условие верно. Используйте утверждения, чтобы убедиться, что определенное условие обязательно соблюдается прежде, чем код исполняется. Если условие является правдой, код выполняется так, как и должен, а если нет, то приложение выключается.
Если ваш код вызывает утверждение в отладочном окружении, т.е., например, при запуске в XCode, то вы сможете увидеть конкретное место и состояние, вызвавшее падение приложения. Утверждение так же позволяет вам предоставить подходящее отладочное сообщение, отражающее натуру утверждения.
Утверждение пишется, используя глобальную функцию assert. Ему передается функция или выражение, возвращающее true или false, а также сообщение, которое отображается в случае, когда результат выражения или функциии – false.
let age =-3 assert( age >=0,"Возраст человека не может быть меньше 0")// строчка выше заставляет сработать наше утверждение, т.к. возраст указан меньше нуля
В этом примере, исполнение кода продолжится только в случае, если возраст age >= 0, т.е. age должно быть неотрицательным. В случае, если оно отрицательно (как в нашем примере), утверждение будет неверным и завершит наше приложение.
Сообщение можно пропустить:
assert(age>=0)
При этом, сообщение для функции assert не может содержать интерполяцию строк.
Когда стоит использовать утверждения
Используйте их, когда условие потенциально может быть false, но должно обязательно быть true, чтобы код продолжил выполнение нормально. Вот пара примеров:
- Индекс для обращения к элементу коллекции должен быть в пределах коллекции, но может быть выше или ниже пределов
- Значение, передаваемое функции, некорректно и не позволяет нормально ее выполнить
- Опциональная переменная содержит nil, но должна быть нe-nil для успешного выполнения кода.
Для более подробной информации смотрите также “Доступ к элементам коллекции” и “Функции” (как только мы их переведем..)
Утверждения завершают приложение, поэтому они являются эффективным способом, чтобы подсказать, что все необходимые условия всгеда соблюдаются в течение процесса разработки и отловить нужные ошибки, но перед публикацией приложения от них лучше избавиться (поскольку не очень правильно просто брать и вырубать приложение, не сообщив ничего пользователю).
p.s. последнее предложение является вольной трактовкой того, что указано в туториале, но смысл отражает точно – впрочем, буду рад услышать о любых корректировках, пишите на email, указанный ниже
Базовые операторы
Оператор – это специальный символ или фраза, которые Вы используете для проверки, изменения или комбинирования значений. Например, оператор сложения (+) складывает два числа вместе ( как let i = 1 +1 ). Более сложные примеры включают логический оператор и && ( как в if enteredDoorCode && passedRetinScan ) и оператор инкремента ++i, который является упрощенным оператором (shortcut) увеличения значения i на 1.Swift поддерживает большинство стандартных операторов языка C и улучшает несколько возможностей для устранения частых ошибок при программировании. Оператор присваивания (=) не возвращает значение, что предотвращает его ошибочное использование вместо оператора равенста (==). Арифметические операторы (+, –, *, /, % и т.д.) определяют и запрещают переполнение значений, чтобы избежать неожиданных результатов, когда работаешь с числами которые становятся больше или меньше того, что позволяет диапазон принимающей переменной. Вы можете изменять поведение переполнения значения, используя операторы переполнения, которые описаны в Операторы Переполнения.В отличии от C, Swift дает возможность выполнять оператор остатка от деления (%) для чисел с плавающей запятой. Swift также предоставляет два оператора диапазона ( a..b и a…b ), которых не было в C, как упрощенный оператор для выражения диапазона значений.Эта глава описывает самые частые операторы Swift. Продвинутые Операторы охватывает продвинутые операторы Swift и описывает как определить Ваши собственные операторы и написать стандартные операторы для Ваших типов.
Терминология
Операторы бывают унарные, бинарные и тернарные:
- Унарные оперируют одним значением (как например -a). Унарные префиксные операторы определяются сразу перед выражением ( как !b) и унарные постфиксные операторы сразу после ( i++ )
- Бинарные оперируют двумя выражениями ( 2 + 3 ) и только
- Тернарные операторы используют три выражения. Как и в C, в Swift есть только один тернанрный оператор, оператор состояния ( a ? b : c )
В выражении 1 + 2 , + это бинарный оператор, а 1 и 2 – это операнды.
Если правая сторона присваивания это tuple с множеством значений, то его значения сразу раскладываются и присваиваются каждой переменной или константе
- Сложение (+)
- Вычитание (–)
- Умножение (*)
- Деление (/)
Чтобы определить ответ для a % b , оператор % считает следующее уравнение и возвращает остаток как значение
Подставив –9 и 4 в это уравнение, получим:
-9 = (4 x 2) + -1
- Если оператор написан перед переменной, он инкрементирует переменную перед тем как вернуть её значение.
- Если оператор написан после переменной, он инкрементирует переменную после того как вернет значение.
Составные операторы присваивания
Как C, Swift предоставляет составные операторы присваивания, которые комбинируют операторы присваивания с другими операторами. К примеру, присваивание с суммированием(+=):
- Равно ( a == b )
- Не равно ( a !=b )
- Больше чем ( a > b )
- Меньше чем ( a < b )
- Больше чем или равно ( a >= b )
- Меньше чем или равно ( a <= b )
Оператор Закрытого Диапазона
Оператор Полузакрытого Диапазона
- Логическое отрицание ( !a )
- Логическое и ( a && b )
- Логическое или ( a || b )
Логическое Отрицание
Логический Оператор И
Если любое значение false, то общее выражение тоже будет false. По факту, если первое значение false, второе не будет даже вычиcляться, поскольку невозможно чтобы общее выражение стало true . Это известно как быстрая схема вычисления .В этом примере сравниваются две Булевые переменные и доступ разрешен, только если оба значения true:
Логический оператор ИЛИ
Логический оператор или ( a || b ) это оператор, который используется для создания выражений, в которых общее значение будет true, если хотя бы одно из значений true.
Как и логический оператор и, логический или использует быструю схему вычисления.
Если левая сторона выражения true, правая не вычисляется, поскольку правая уже не может изменить общего значения.
В примере ниже, первая Булевая переменная (hasDoorkey) равна false, однако второе значение (knowsOverridePassword) равна true. Поскольку одно значение true, общее выражение также считается true, и доступ разрешен:
Комбинирование Логических Операторов
Вы можете комбинировать несколько логических операторов, чтобы увеличить количество сравнений:
Если enteredDoorCode и passedRetinaScan; или если hasDoorKey ; или если knowsOverridePassword, то выполнить println(“Welcome”), иначе println(“Access Denied”).
Основываясь на enteredDoorCode, passedRetinaScan, and hasDoorKey, первые два выражения
false. Однако, knowsOverridePassword true, а значит и всё выражение true.
Явные скобки
Иногда полезно использовать скобки, когда они не необходимы, чтобы сделать общее выражение более читаемым. В верхнем выражении полезно добавить скобки в первую часть общего выражения, чтобы явно выделить выражение:
Скобки делают понятнее, что первые два значения являются частью общего разделенного выражения. Вывод объединного выражения не изменяется, однако общий замысел более понятен читающему. Читаемости всегда отдается предпочтение перед краткостью; используйте скобки там, где они помогают сделать идею более ясной.
Строки и символы
Строка – это упорядоченная коллекция (набор) символов, например “hello, world” или “альбатрос”. Строки в Swift представлены типом String, который, в свою очередь, представляет собой коллекцию значений типа Character.
Типы String и Character в Swift предоставляют быстрый, совместимый с юникодом способ работать с текстом в вашем коде. Синтаксис для создания и манипуляций со строками легкий и читабельный, со схожим синтаксисом для С-строк. Для конкатенации (сложения двух строк вместе) достаточно просто сложить их, используя оператор +, а изменяемость строк (возможность модифицировать существующую строку) определяется тем, хранится ли она в константе или в переменной – как и для любого другого типа в Swift.
Несмотря на простоту синтаксиса, String в языке имеет быструю и современную реализацию – каждая строка состоит из независимых от кодировки юникод-символов и предоставляет поддержку для доступа к этим символам в разных юникод-представлениях (unicode representations).
Строки также могут быьт использованы для вставки констант, переменных, литералов и выражений в более длинные строки – это называется “строковая интерполяция”. Это позволяет легко создавать собственные строковые значения для вывода, хранения и печати.
String в Swift’e “внутри” бесшовно сшит (bridged) с классом NSString. Если вы работаете с Foundation в Cocoa или Cocoa Touch, весь API NSString доступен вам для каждой создаваемой вами String в свифте – и это помимо всех функций String, которые описываются в этой главе. Вы также можете использовать String для любых API, в которых используется NSString. Для более подробной информации об использовании String с Foundation и Cocoa, обратитесь к “Используем Swift с Cocoa и Objective-C”.
Строковые литералы
Вы можете включить предопределенные строковые значения в вашем коде как строковые литералы. Строковый литерал – это какая-либо зафиксированная последовательность текстовых символов, окруженная парой кавычек.
Строковый литерал может быть использован в качестве начального значения для константы или переменной:
let someString ="Some string literal value"
Обратите внимание, что Swift сам автоматически определит тип String для someString, поскольку мы инициализировали ее с помощью строкового литерала.
Строковые литаралы могут включать следующие специальные символы:
- Специальные символы \0 (null), \\ (бэкслэш), \t (горизонтальная табуляция), \n (перенос строки), \r (возврат каретки), \” (двойная кавычка), \’ (одиночная кавычка).
- Однобайтовые юникод-скаляры, записанные как \xNN, где NN – две шестнадцатеричных цифры.
- Двухбайтные юникод-скаляры, записанные как \uNNNN, где NNNN – четыре шестнадцатеричных цифры.
- Четыребайтные юникод-скаляры, записанные как \UNNNNNNNN, где NNNNNNNNN – восемь шестнадцатеричных цифр.
Код ниже показывает пример кажого специального символа. Константа wiseWords содержит цитату в кавычках. doollarSign, blackHeart и sparklingHeart показывают использование разных юникод-скаляров. Примечание переводчика: чтобы посмотреть на скаляры, лучше запустить эту радость у себя в XCode. Я попозже выдерну сюда картинку, но пока я этого не сделал – лучше посмотреть в xcode :)
let wiseWords ="\"Imagination is more important than knowledge\" - Einstein"// "Imagination is more important than knowledge" - Einstein let dollarSign ="\x24"// $, Unicode scalar U+0024 let blackHeart ="\u2665"// ?, Unicode scalar U+2665
Инициализация пустой строки
Чтобы создать пустое значение String как стартовую точку для создания более длинной строки – либо присвойте пустой строковый литерал переменной, либо создайте новый объект String с помощью синтаксиса инициализации:
var emptyString =""// пустой строковый литерал var anotherEmptyString =String()// синтаксис инициализации // обе строки пусты и эквивалентны друг другу
Можно узнать, пуста ли строка, обращаясь к свойству isEmpty:
if emptyString.isEmpty { println("Nothing to see here")}// выведет Nothing to see here
Изменение строк
Вы можете решить, будет ваша строка модифицируемой или нет, присвоив ее переменной или константе (соответственно, модифицируется если переменная и нет, если константа):
var variableString ="Horse" variableString +=" and carriage"// variableString теперь "Horse and carriage" let constantString ="Highlander" constantString +=" and another Highlander"// это вызовет ошибку компилятора, поскольку нельзя модифицировать константу
Этот подход отличается от модифицируемости строк в objective-c, где вам нужно было выбирать между двумя классами – NSString и NSMutableString – чтобы определить, будет ли строка модифицируемой.
Строки это тип-значение
В Swift тип String – это тип-значение (value type – не заморачивайтесь на тему самого термина, главное – это вывод, который сейчас из этого последует – прим. переводчика). Если вы создаете новую строку String, ее значение копируется, когда оно передается в функцию или метод или когда присваивается константе или переменной. В любом случае, копия существующей строки создается и затем передается или присваивается.. а не ее оригинал. Типы-значения описаны в разделе “Структуры и перечисления – это типы-значения”.
Это поведение отличается от NSString в Cocoa – там, при создании NSString-объекта и передаче его в функцию или при присвоении переменной, вы всегда передавали или присваивали ссылку на один и тот же объект NSString. Копирования не происходило, если только вы специально это не указывали.
Подход Swift “копируем по умолчанию” позволяет быть уверенным, что если функция или метод передали вам значение String, то это – ваше значение и что оно не будет модифицировано где-либо еще.
“Глубоко внутри” (при компиляции), компилятор языка оптимизирует использование строк так, чтобы само копирование происходило только когда оно абсолютно необходимо, что означает хорошую производительность при работе со строками как со значениями.
Работа с символами
String представляет собой коллекцию значений Character с обозначенным порядок. Каждое значение Character представляет собой один юникод-символ. Вы можете получить доступ к каждому символу Character, например, используя итерацию по всей строке с помощью for-in:
for character in"Dawg!"{ println(character)} // D // a // w // g // !
for-in описывается в разделе “Циклы for“.
Как вариает, вы можете создать отдельный символ Character как константу или переменную, используя односимвольный строчный литерал:
let yenSign:Character="?"
Подсчет символов
Чтобы получить количество символов в строке, вызовите глобальную функцию countElements и передайте ей строку в качестве параметра:
let unusualMenagerie ="Koala , Snail , Penguin , Dromedary " println("unusualMenagerie имеет \(countElements(unusualMenagerie)) символов")// печатает "unusualMenagerie имеет 40 символов"
Различные символы юникода и различные представления одного и того же символа юникода могут занимать различное количество памяти. Из-за этого, символы в Swift не занимают одинаковое количество памяти в строке и, в результате, длина строки не может быть подсчитана без итерации по всей строке и подсчета каждого символа. Если вы работаете с особенно длинными строками, помните, что countElements должна пройти по всем символам в строке, чтобы точно подсчитать количество символов в ней.
Помните также, что количество символов, возвращаемое функцией countElements, не всегда совпадает со свойством length объекта NSString, содержащего эти символы. Длина NSString базируется на количестве 16-битных едениц кода внутри UTF-16 представления строки, а не на количестве юникод-символов в строке. Чтобы отобразить этот факт, свойство length из NSString вызывается с помощью utf16count объекта String
Конкатенация строк и символов
String и Character могут быть сложены вместе (конкатенированы) с помощью знака +, чтобы создать новое значение String:
let string1 ="hello" let string2 =" there" let character1:Character="!" let character2:Character="?" let stringPlusCharacter = string1 + character1 // "hello!" let stringPlusString = string1 + string2 // "hello there" let characterPlusString = character1 + string1 // "!hello" let characterPlusCharacter = character1 + character2 // "!?
Вы можете также добавить String или Character к существующей переменной String с помощью оператора +=:
var instruction ="look over" instruction += string2 // instruction теперь "look over there" var welcome ="good morning" welcome += character1 // welcome теперь "good morning!
Вы не можете добавить String или Character к существующей переменной Character, т.к. она должна содержать только один символ.
Интерполяция строк
Интерполяция строк – это способ создать новое значение String из смеси констант, переменных, литералов и значений, включая их все в один строчный литерал. Каждый элемент, который вы включаете, заключается в \():
let multiplier =3 let message ="\(multiplier) умножить на 2.5 равно \(Double(multiplier) * 2.5)"// message теперь "3 умножить на 2.5 равно 7.5"
В примере выше, значение multiplier вставляется в строковый литерал как \(multiplier). Оно заменяется на значение самой переменной, когда выполняется строковая интерполяция для создания самой строки.
Значение multiplier также используется в выражении далее в строке – выражение вычисляет значение Double(multiplier) * 2.5 и вставляет результат (7.6) в строку. В данном случае оно тоже записывается внутри \(), т.е. \(Double(multiplier) * 2.5), когда вставляется в строковый литерал.
Выражения, которые вы пишите внутри скобок в интерполированной строке, не могут содержать кавычки “, бэкслэш \ и не могут содержать перенос строки.
Сравнение строк
Swift предоставляет три способа сравнивать строковые значения: равенство строк, равенство префикса и равенство суффикса.
Равенство строк
Два значения String считаются равными, если они содержат одинакоавые символы в одинаковой последовательности:
let quotation ="We're a lot alike, you and I." let sameQuotation ="We're a lot alike, you and I." if quotation == sameQuotation { println("Эти две строки - одинаковые")}// выводит "Эти две строки - одинаковые"
Равенство суффикса и префикса
Чтобы проверить, имеет ли строка определенный префикс или суффикс, вызовите методы hasPrefix и hasSuffix, каждый из которых принимает один аргумент типа String и возвращает Boolean значение. Оба метода выполняют посимвольное сравнение между строкой и префиксом/суффиксом.
Примеры ниже представляют собой массив строк, представляющий собой расположение сцен в первых двух актах пьесы “Ромео и Джульетта” Шекспира (спасибо Apple за потрясающую возможность хоть немного познакомиться с великой пьесой – прим. переводчика):
let romeoAndJuliet =["Act 1 Scene 1: Verona, A public place","Act 1 Scene 2: Capulet's mansion","Act 1 Scene 3: A room in Capulet's mansion","Act 1 Scene 4: A street outside Capulet's mansion","Act 1 Scene 5: The Great Hall in Capulet's mansion","Act 2 Scene 1: Outside Capulet's mansion","Act 2 Scene 2: Capulet's orchard","Act 2 Scene 3: Outside Friar Lawrence's cell","Act 2 Scene 4: A street in Verona","Act 2 Scene 5: Capulet's mansion","Act 2 Scene 6: Friar Lawrence's cell"]
Вы можете использовать метод hasPrefix с элементами массива, чтобы посчитать количество сцен первого акта пьесы:
var act1SceneCount = 0 for scene in romeoAndJuliet { if scene.hasPrefix("Act 1 ") { ++act1SceneCount } } println("В первом акте \(act1SceneCount) сцен") // в первом акте 5 сцен
Аналогично, hasSuffix поможет нам подсчитать, сколько сцен происходит вокруг поместья Капулетти и в клетке Фраяра Лоуренса:
var mansionCount =0 var cellCount =0 for scene in romeoAndJuliet { if scene.hasSuffix("Capulet's mansion") { ++mansionCount } else if scene.hasSuffix("Friar Lawrence's cell") { ++cellCount } } println("Сцен в поместье \(mansionCount), сцен в клетке - \(cellCount)")// 6 сцен в поместье, 2 - в клетке
ПРОПИСНЫЕ и строчные буквы в строках
Вы можете получить доступ к ПРОПИСНОЙ версии строки или к строчной, используя свойства uppercaseString и lowercaseString:
let normal ="Could you help me, please?" let shouty = normal.uppercaseString // shouty is equal to "COULD YOU HELP ME, PLEASE?" let whispered = normal.lowercaseString // whispered is equal to "could you help me, please?
Юникод
Юникод – это международный стандарт кодировки и представления текста. Он позволяет вам представить практически любой символ из любого языка в стандартизированной форме и читать и писать эти символы из/во внешний источник, например текстовый файл или веб-страницу.
Swift’овские типы String и Character полностью юникод-совместимы. Они поддерживают несколько различных юникод-кодировок, как описано ниже.
Терминология юникода
Каждый символ в юникоде может быть представлен одним или несколькими юникод-скалярами. Юникод-скаляр – это уникальное 21-битное число (и название) для символа или модификатора, например U+0061 для LOWERCASE LATIN LETTER A(прописная латинская буква A – “a”), или U+1F425 для FRONT-FACING BABY CHICK (цыпленой, стоящий к нам лицом… – в некоторых браузерах, он может отображаться как квадратик. воспользуйтесь файрфоксом или дождитесь, когда я отредактирую сайт и вставлю картинки.. или скопируйте этот символ в XCode).
Когда юникод-строка записывается в текстовый файл или другое хранилище, эни скаляры кодируются в один из юникод-форматов. Каждый из этих форматов кодирует строку в виде малкеньких кусочков, известных как “юниты кода” (или куски кода, или части кода – как вам угодно). Эти форматы – UTF-8 (кодирует строку как 8-битные юниты) и UTF-16 (кодирует строку как 16-битные юниты).
Юникод-представления строк
Swift предоставляет несколько способов доступа к юникод-представлениям строк.
Вы можете пройти циклом по строке с помощью for-in для доступа к индивидуальным Character-значениям как к юникод-символам. Этот процесс описывается в разделе “Работа с символами” на нашем сайте.
Также, можно получить доступ к значению String в одном из трех юникод-совместимых представлениях:
- Коллекция UTF-8 юнитов кода (доступ через свойство utf8)
- Коллекция UTF-16 юнитов кода (доступ через свойство utf16)
- Коллекция 21-битных юникод-скаляров (доступ через свойство unicodeScalars)
В каждом из примеров ниже, посмотрим на различные представления строки, составленной из символов D,o,g,! и значка (DOG FACE, лицо собаки, символ U+1F436):
let dogString ="Dog!"
UTF-8
Вы можете получить доступ к UTF-8 представлению строки, пройдясь циклом по свойству utf8. Это свойство имеет тип UTF8View, который является коллекцией беззнаковых 8-битных (UInt8) значений, по одному на каждый байт в UTF-8 представлении строки:
for codeUnit in dogString.utf8 { print("\(codeUnit) ") } print("\n")// 68 111 103 33 240 159 144 182
В примере выше, первые четыре десятичных значения codeUnit (68, 111, 103, 33) представляют символы D, o, g, !, чье UTF-8 представление такое же, как и их ASCII представление. Последние четыре значения codeUnit (240, 159, 144, 182) – это 4-байтное UTF-8 представление символа “морда пса”.
UTF-16
Вы можете получить UTF-16 представление, опять же работая со свойством urf16. Оно имеет тип UTF16View, которое является коллекцией беззнаковых 16битных значений UInt16, каждое для 16-битного юнита в UTF-16 представлении строки:
for codeUnit in dogString.utf16 { println("\(codeUnit)") } print("\n")// 68 111 103 33 55357 56374
Опять же, первые четыре номера – это символы D,o,g,!, которые в UTF-16 имеют то же значение, что и в UTF-8.
Пятый и шестой номер – это UTF-16-представление символа “морда пса”. ОНи называются “суррогатным парным представлением”, состоящим из ведущего суррогатного значения U+D83D (55357) и замыкающего суррогатного значения U+DC36 (56374). (от переводчика: идея в общем в том, что в конечном счете это четыре байта, которые представляют собой номер смайлика с собакой)
Юникод-скаляры
Вы можете работать с юникод-скалярным представлением строки, используя свойство unicodeScalars – оно имеет тип UnicodeScalarView, которое является коллекцией элементов типа UnicodeScalar. Юникод-скаляр – это любой 21-битный юникод, который не является частью суррогата.
Каждый UnicodeScalar имеет свойство value, которое возвращает 21-битное значение скаляра, представляемое как UInt32:
for scalar in dogString.unicodeScalars { print("\(scalar.value) ") } print("\n")// 68 111 103 33 128054
Свойства value для первых четырех скаляров это известные нам символы D,o,g,!. Значчение последнего – 128054 – это десятичный эквивалент шестнадцатеричного 1F436, что эквивалентно юникод-скаляру U+1F436, обозначающему смайл DOG FACE.
Альтернативный вариант для доступа к свойству value – сконструировать новое значение String с помощью, например, строковой интерполяции:
for scalar in dogString.unicodeScalars { println("\(scalar) ")}// D// o// g// !//
Управление хода выполнения
Swift предоставляет все знакомые нам с С-подобных языков элементы, позволяющие управлять ходом выполнения приложения. Они включают циклы for и while для многократного выполнения задачи, if и switch для выполнения разных частей кода в зависимости от условий, а также break и continue для перемещения выполнения в другую точкку кода.
В дополнение к традиционному for-условие-инкремент циклу из С, Swift добавляет for-in цикл, позволяющий легко производить итерацию по элеметнам массивов, словарей, диапазонов, строк и других последовательностей.
Switch в Swift также более значительный, чем его “собрат” из С. Кейсы в switch (кейс – условие, которое мы проверяем для заданной переменной) не переходят автоматом к следующему кейсу, позволяя избежать частой в С ошибки, вызываемой пропуском break. Кейсы могут соответствовать многим разным типам шаблонов, включая соответствия диапазонам, кортежам, а также конвертациям к другому типу. Значения, которые нашли соответствие в switch-кейсе, могут быть пивязаны ко временным константам или переменным, чтобы мы могли их использовать внутри кейса, а сложные условия в case могут быть выражены с помощью where для каждого случая.
(если вы ничего не поняли из параграфа выше – не пугайтесь, в коде будет все понятно, просто читайте дальше – прим. переводчика)
Циклы for
for выполняет кусок кода определенное количество раз. Swift предоставляет два типа циклов for:
- for-in выполняет определенный код для каждого элемента в диапазоне, последовательности, коллекции или прогрессии
- for-условие-инкремент выполняет кусок кода, пока не будет выполнено определенное условие, обычно увеличивая счетчик в конце каждого цикла
for-in
Вы можете использовать for-in цикл для итерации по коллекции элементов, например по диапазонам чисел, элементам массива или символам в строке.
Пример ниже печатает первые несколько элементов в виде таблицы умножения на 5:
for index in 1...5{ println("\(index) X 5 = \(index * 5)")} // 1 X 5 = 5 // 2 X 5 = 10 // 3 X 5 = 15 // 4 X 5 = 20 // 5 X 5 = 25
Коллекция элементов, по которой происходит итерация, это закрытый диапазон от 1 до 5 включительно, поскольку мы используем оператор закрытого диапазона – … Значение index устанавливается первому элементу из диапазона(1), затем выполняется код из цикла (код печати на экран, в нашем случае). Затем значение index обновляется на второй элемент из диапазона (2) и снова выполняется код из цикла – и так происходит, пока не будет достигнут конец диапазона.
В примере выше, index – это константа, чье значение автоматически устанавливается в начале каждой итерации цикла, поэтому мы не объявляем ее перед ее использованием – она неявно объявляется тем, что мы использовали ее в нашей записи for-in.
Обратите внимание! Эта константа существует только внутри цикла. Если вы хотите работать с ней после окончания цикла или хотите работать с ней как с переменной, вам нужно самим объявить ее _перед_ циклом, а затем использовать в цикле.
Если вам не нужно каждое значение в диапазоне, вы можете игнорировать значения, используя подчеркивание вместо имени переменной:
let base =3 let power =10 let answer =1 for _ in 1...power { answer *=base } println("\(base) в степени \(power) = \(answer)")// 3 в степени 10 равно 59049
Этот пример считает степень числа (в нашем случае, 3 в степени 10). Он умножает стартовое значение 1 (это 3 в степени 0) на 3 – и делает это 10 раз, используя полу-закрытый цикл, начинающийся 0 и заканчивающийся 9 (примечание переводчика: тут косяк книжки – цикл закрытый и идет от 1 до 10 включительно. чтобы записать полу-закрытый цикл от 0 до 9, мы бы написали – for _ in 0..power – результат одинаковый, но запись разная). Этот подсчет не требует значения счетчика, ему лишь важно, чтобы цикл был запущен нужное количество раз, поэтому мы используем символ поддчеркивания _ для того, чтобы игнорировать значения счетчика.
Используйте for-in, чтобы совершать итерации по элементам массива:
let names =["Anna","Alex","Brian","Jack"] for name in names { println("Hello, \(name)!")} // Hello, Anna! // Hello, Alex! // Hello, Brian! // Hello, Jack!
Вы также можете проводить итерацию по словарю, чтобы получить доступ к парам ключ-значение. Каждый элемент в словаре возвращается как кортеж (key, value) (ключ и значение), когда происходит итерация по словарю, и вы можете декомпозировать кортеж в виде именованных констант прямо в тексте for-in – в примере это воспринимается легче:
let numberOfLegs =["паук":8,"муравей":6,"кот":4] for(animalName, legCount) in numberOfLegs { println("\(animalName) имеет \(legCount) лап")} // паук имеет 8 лап // муравей имеет 6 лап // кот имеет 4 лап
Элементы в словаре не обязательно будут пройдены циклом в том же порядке, в котором они добавлялись – содержимое в словаре является по своей природе неупорядоченным и итерация по его элементам не гарантирует никакого порядка в том, как они будут выданы в цикл. Для дополнительной информации о массивах и словарях, смотрите раздел “Типы коллекций” на нашем сайте.
В дополнение к словарям и массивам, вы можете использовать for-in для итерации по символам Character строки:
for character in"Hello"{ println(character)} // H // e // l // l // o
For-условие-инкремент
В дополнение к for-in циклам, Swift поддерживает стандартный для С цикл for с условием и инкрементом:
for var index =0; index <3;++index { println("index is \(index)")} // index is 0 // index is 1 // index is 2
Вот общий формат этого типа циклов:
for инициализация ; условие ; инкремент { код }
Точки с запятой разделяют три части определения цикла, как в С. Однако, в отличие от С, Swift не нуждается в скобках вокруг блога “инициализация; условие; инкремент”.
Цикл исполняется следующим образом:
- Когда выполнение впервые добирается до цикла, запускается код “иницализации” единственный раз, и он устанавливает любые необходимые циклу константы или переменные
- Затем происходит проверка условия. Если условие ложно (false), цикл завершается (возможно, так и не выполнившись ни разу), если же true – то весь код внутри скобок {} выполняется.
- После того, как весь код цикла выполнен, происходит инкремент (или любое другое действие, чаще всего это все же увеличение или уменьшение счетчика) или выставление нового значения для одной из инициализированных переменных. И мы возвращаемся к шагу 2 для проверки условия.
Этот цикл эквивалентен следующей записи цикла while:
_инициализация_ while _условие_ { _вашкод_ _инкремент_ }
Константы и переменные, объявленные в процессе инициализации, существуют только в пределах цикла for. Чтобы получить финальное значение, к примеру, переменной index из кода выше, нам надо объявить ее до того, как начнется цикл:
var index:Int for index =0; index <3;++index { println("index is \(index)")} // index is 0 // index is 1 // index is 2 println("Цикл исполнен \(index) раз(а)") // Цикл исполнен 3 раз(а)
Обратите внимание, что финальное значение index после завершения цикла – 3, а не 2. Последний инкремент ++index был вызван, установил index в 3, поэтому index < 3 стало false и цикл завершился.
Цикл for выполняет одну или несколько строк кода определенное количество раз. Swift предоставляет два типа цикла for:
- for-in выполняет код для каждого элемента в диапазоне, последовательности, коллекции или прогрессии
- for-условие-инкремент выполняет код, пока определенное условие не будет выполнено, обычно увеличивая счетчик, пока не закончится цикл
Циклы while
Цикл while исполняет код, пока условие не становится false. Эти циклы лучше всего используются, когда мы заранее не знаем количество повторений. Swift предоставляет нам два типа цикла while:
- while цоенивает условие перед исполнением каждой итерации
- do-while оценивает условие после исполнения каждой итерации
While
Цикл while начинается с оценки условия. Если условие верно (true), то код внутри {} будет выполняться, пока условие не станет false.
Вот общая форма цикла while:
while _условие_ { _вашкод_ }
Вот пример из простой игры “Змеи и лестницы” (еще известна как “горки и лестницы”):
Правила игры таковы:
- Доска имеет 25 квадратов и цель – дойти до квадрата 25 или далее.
- Каждый ход вы бросаете кубик и передвигаетесь на столько квадратов, сколько выпадет на кубике, двигаясь по стрелке на картинке.
- Если вы очутились на картинке, на которой нарисован низ лестницы, вы передвигаетесь вверх по этой лестнице.
- Если ваш ход закончился на голове змеи, вы передвигаетесь вниз к хвосту змеи.
Доска представлениа массивом значений Int. Его размер основан на константе finalSquare, которая используется для инициализации массива и для проверки на победу далее в примере. Доска инициализируется 26 нулями, а не 25 (по одному нулю от 0 до 25 индекса включительно):
let finalSquare =25 var board =Int[](count: finalSquare +1, repeatedValue:0)
Некоторые квадраты затем устанавливаются в другие значения, представляя собой змей и лестницы. Квадраты с лестницами содержат положительное число, чтобы пондять вас вверх по доске, тогда как квадраты со змеями содержат отрицательное число, чтобы передвинуть вас назад:
board[03]=+08; board[06]=+11; board[09]=+09; board[10]=+02 board[14]=-10; board[19]=-11; board[22]=-02; board[24]=-08
Квадрат 3 содержит из лестницы, которая переместит вас на квадрат 11. Чтобы отобразить это в коде, мы присваиваем board[03] (третий квадрат) число 8 – т.е. разницу между 3 и 11. Мы записали его как +08, но это не обязательно – можно было бы написать просто 8; запись +08 помогла нам отформатировать все значения красиво (ох Apple, как заботятся о красоте, даже в коде! ну и правильно, на самом деле. – прим. переводчика)
Игроки начинают с квадрата board[0], который не показан на рисунке – это просто стартовая точка в левом нижнем углу доски. Первый бросок всегда передвигает игрока по доске:
var square =0 var diceRoll =0 while square < finalSquare { // кидаем кубик if ++diceRoll == 7{ diceRoll =1}// двигаемся на нужное кол-во клеток вперед square += diceRoll if square < board.count {// если мы еще на доске, двигаемся вверх по лестнице или вниз по змее (если они есть в этой клетке) square += board[square]} } println("Игра закончена!")
Этот пример использует очень простой подход к бросанию кубика. Вместо генерации случайного заначения, мы просто начинаем со значения 0 и в каждом цикле увеличиваем на 1, а когда значение становится большим (7), сбрасываем его. Выражение ++diceRoll возвращает значение diceRoll _после_ инкремента. Таким образом, мы получаем значения 1, 2, 3, 4, 5, 6, 1, 2, 3 и т.д.
После броска кубика, игрок продвигается вперед на diceRoll квадратов. Возможно, что таким образом он выйдет за пределы доски – тогда игра окончена. Чтобы понять это, мы сравниваем square (номер квадрата) с общим количеством квадратов на доске (свойство count), и только после этого (если игрок не вышел за пределы) мы добавляем к его текущему квадрату дополнительные клетки (или отнимаем их), обозначая движение по лестнице или по змее.
Если бы мы не выполняли проверку на выход за пределы доски, выражение board[square] могло бы обратиться за пределы массива – что вызвало бы ошибку. Если square равен 26, код попробовал бы обратиться к board[26] – это больше размера массива.
Затем код в цикле заканчивается и снова наступает проверка значения в while. Если игрок вышел за пределы клетки 25 (или дошел до нее), условие становится false и игра заканчивается. Цикл while подходит для этого случая, поскольку мы заранее не знаем длину игры (количество ходов). Вместо этого, цикл исполняется, пока определенное условие удовлетворено.
Do-While
Другая вариация цикла while известна как do-while. Она выполняет один проход по телу цикла до того, какпроверяет условие. После этого, он продолжает выполнять цикл, пока условие не станет false.
Вот общая форма цикла do-while:
do {код} while условие
Обратимся снова к примеру нашей игры про змей и лестницы, написанной в стиле do-while, а не while. Значения finalSquare, board, square и diceRoll инициализируются в точности как в случае while:
let finalSquare =25 var board =Int[](count: finalSquare +1, repeatedValue:0) board[03]=+08; board[06]=+11; board[09]=+09; board[10]=+02 board[14]=-10; board[19]=-11; board[22]=-02; board[24]=-08 var square =0 var diceRoll =0
В этой версии игры, первое действие в цикле проверяет на змею или лестницу. У нас нет ни одной лестницы или змеи, которая перенесла бы игрока прямо на клетку 25 и поэтому невозможно выиграть игру, просто встав на лестницу. Поэтому, проверять безопаснее, когда змея или лестница является первым действием в цикле. (примечание переводчика: новичкам, возможно, сложновато будет понять логику всего этого. если это так – не зацикливайтесь, основная идея главы – дать вам информацию о циклах, а не о том, как писать код игры.)
После начала игры, игрок находится на нулевой клетке. board[0] всегда равняется 0 и не имеет эффекта:
do{// двигаемся наверх по лестнице или вниз по змее (или не двигаемся вообще) square += board[square]// кидаем кубик if ++diceRoll == 7 { diceRoll =1}// передвигаем игрока на нужное кол-во клеток вперед square += diceRoll }while square < finalSquare println("Игра закончена!")
После того, как код проверил на змей и лестницы, мы кидаем кубик и передвигаем игрока вперед на diceRoll клеток. Затем цикл заканчивается.
Условие цикла (while square < finalSquare) такое же, как и раньше, но в этот раз оно проверяется в концепервого прохождения цикла. Структура do-while лучше соответствует этой игре, чем обычный цикл while. В do-while, square += board[suqare] исполняется сразу после условия while и мы можем быть уверены, что игрок еще находится на доске. Это поведение убирает необходимость проверки на границы массива, с которой мы столкнулись в реализации с while.
Условные выражения
Часто полезно исполнять разные части кода, основываясь на определенных условиях. Возможно, вы хотите запустить код, если произошла ошибка, или отобразить сообщение, когда значение становится слишком большим или слишком низким. В этих случаях, вам надо сделать часть вашего кода условной
Swift предоставляет два способа добавить условные ветки в ваш код, известные как if и switch. Обычно вы будете использовать if, чтобы оценивать простые условия с небольшим возможным вариантом исходов. Switch позволяет оценивать ссложные условия со многими возможными перестановками и подходит в ситуациях, когда поиск по шаблону позволяет выбрать необходимых кусок кода для выполнения.
If
В самой простой своей форме, If содержит единственное условие. Он исполняет набор выражений только в случае, если условие верно (true):
var temperatureInFahrenheit =30 if temperatureInFahrenheit <=32 { println("Очень холодно, оденьте шарф.")}// печатает фразу
В данном примере мы сравниваем температуру (по Фаренгейту) с 32 градусами (точка замерзания воды). В случае, если условие верно – сообщение печатается. В обратном случае, сообщение не печатается и выполнение кода продолжается сразу после закрывающей }.
Условие if может предоставлять альтернативный код, исполняемый, когда условие неверно – для этого используется ключевое слово else. Посмотрим пример:
var temperatureInFahrenheit =40 if temperatureInFahrenheit <=32{ println("Очень холодно, оденьте шарф.")}else{ println("Не очень холодно, идите в носках")}// печатает фразу про носки
Одна из этих двух ветвей кода всегда будет выполнена. Поскольку температура задана 40, условие <= 32 становится неверным, поэтому исполняется код ветки else.
Вы можете соединить несколько if-ветвей вместе:
temperatureInFahrenheit =90 if temperatureInFahrenheit <=32{ println("It's very cold. Consider wearing a scarf.")} else if temperatureInFahrenheit >=86{ println("It's really warm. Don't forget to wear sunscreen.")} else{ println("It's not that cold. Wear a t-shirt.")} // печатает "It's really warm. Don't forget to wear sunscreen.
Здесь, дополнительные if используются, чтобы сообщать нам об особенно высоких температурах. Финальный else остается и печатает сообщение для любых температур, не слишком теплых и не слишком холодных.
Финальный else не обязателен, можно вполне обойтись без него и это не вызовет ошибку:
temperatureInFahrenheit =72 if temperatureInFahrenheit <=32{ println("It's very cold. Consider wearing a scarf.")} else if temperatureInFahrenheit >=86{ println("It's really warm. Don't forget to wear sunscreen.")}
В данном примере. температура не слишком холодная и не слишком теплая, поэтому ни одно из условий не выполняется и ничего не печатается на экране.
Switch
Switch берет некоторое значение и сравнивает его c разными возможнами вариантами значений или шаблонами. Затем исполняет подходящий блок кода – первый блок, который будет соответствовать условию. Switch – это альтернатива if, используемая, чтобы отвечать на множество возможных состояний.
В самой простой форме switch просто сравнивает значение с другими возможными значениями того же типа:
switch некоторое_значение { case вариант_1: код case вариант_2,вариант_3: код default: код, выполняемый, если другие варианты не совпали }
Каждый switch состоит из нескольких возможных cases, то есть случаев. Каждый возможный случай начинается с ключевого слова case. В дополнение к сравнению с указанным значением, Swift предоставляет несколько способов сопоставлять значение с более сложными шаблонами соответствия. Эти опции будут описаны далее в этой главе.
Тело каждого случая в switch’е – это отдельная ветвь кода, так же как и каждая отдельная ветвь в if. Switch определяет, какая из веток будет выбрана – это называется переключение(англ. switching) на значение, которое мы рассматриваем.
Каждый switch должен быть исчерпывающим. То есть, любое возможное значение типа должно быть рассмотрено нашими case’ами. Если невозможно рассмотреть абсолютно все варианты, вы можете определить кейс “по умолчанию”, чтобы покрыть все оставшиеся значения. Такой кейс определяется с помощью ключевого слова default и должен всегда стоять в конце.
В данном примере используем switch, чтобы рассмотреть константу someCharacter:
let someCharacter:Character="e" switch someCharacter { case"a","e","i","o","u": println("\(someCharacter) - гласная буква") case"b","c","d","f","g","h","j","k","l","m","n","p","q","r","s","t","v","w","x","y","z": println("\(someCharacter) - согласная буква") default: println("\(someCharacter) - это не гласная и не согласная буква") } // напечатает "e - гласная буква"
Switch в первом своем случае-кейсе рассматривает все пять строчных (А НЕ ПРОПИСНЫХ) гласных букв английского языка. Аналогично, второй кейс рассматривает все строчные согласные буквы английского языка.
Непрактично писать все остальные возможные символы для всех остальных случаев, поэтому мы используем default, чтобы обозначить случай для всех остальных символов. Таким образом мы убеждаемся, что наш switch покрывает все возможные варианты.
Нет неявных переходов
В отличие от switch в С и Objective-C, в Swift утверждения в switch, после окончания, не переходят автоматически к выполнению следующего. (примечание переводчика: если бы мы писали пример с гласными-согласными в С, то после выполнения кода из первого кейса, без специального ключевого слова у нас бы выполнились кейсы 2 и 3, в Свифте этого нет). Вместо этого, switch заканчивает выполнение кода сразу как закончился первый подходящий кейс, не требуя ключевого слова break, что позволяет всему switch быть безопаснее и проще в использовании, чем в С и избегает выполнения нескольких кейсов по ошибке.
Вы по-прежнему можете использовать break для выхода из вашего кейса, если это необходимо. Об этом – далее в этой главе.
Тело каждого кейса должно содержать как минимум одно исполняемое утверждение. Нельзя написать следующий код, т.к. первый кейс не содержит ни одной исполняемой строки:
let anotherCharacter:Character="a" switch anotherCharacter { case"a": case"A": println("The letter A") default: println("Not the letter A") } // будет вызвана ошибка компилятора
В отличие от switch в С (где мы таким образом выполняли бы один и тот же код для букв “а” и “А”, здесь компилятор сообщит нам об ошибке. Такой подход позволяет не допустить случайного перехода от одного кейса к другому и помогает содержать код чистым и понятным.
Если нам необходимо задать несколько значений в нашем кейсе, мы можем разделить их запятыми и перенести на несколько строк:
switch выражение { case значение_1, значение_2: код }
Вы можете использовать неявные переходы как в С для вашего switch, для этого вам необходимо использовать ключевое слово fallthrough – об этом подробнее написано в разделе “Неявный переход fallthrough”.
Информация взята с сайта swift-info.ru