diff --git a/ru-ru/swift-ru.html.markdown b/ru-ru/swift-ru.html.markdown index 05f4936c..7ff660e1 100644 --- a/ru-ru/swift-ru.html.markdown +++ b/ru-ru/swift-ru.html.markdown @@ -4,9 +4,11 @@ contributors: - ["Grant Timmerman", "http://github.com/grant"] - ["Christopher Bess", "http://github.com/cbess"] - ["Joey Huang", "http://github.com/kamidox"] + - ["Alexey Nazaroff", "http://github.com/rogaven"] filename: learnswift-ru.swift translators: - ["Dmitry Bessonov", "https://github.com/TheDmitry"] + - ["Alexey Nazaroff", "https://github.com/rogaven"] lang: ru-ru --- @@ -21,6 +23,8 @@ Swift - это язык программирования, созданный к Смотрите еще [начальное руководство](https://developer.apple.com/library/prerelease/ios/referencelibrary/GettingStarted/RoadMapiOS/index.html) Apple, которое содержит полное учебное пособие по Swift. ```swift +// Версия Swift: 3.0 + // импорт модуля import UIKit @@ -31,10 +35,14 @@ import UIKit // Xcode поддерживает маркеры, чтобы давать примечания своему коду // и вносить их в список обозревателя (Jump Bar) // MARK: Метка раздела +// MARK: - Метка с разделителем // TODO: Сделайте что-нибудь вскоре // FIXME: Исправьте этот код -println("Привет, мир") +// Начиная со второй версии Swift, println и print объединены в методе print. +// Перенос строки теперь добавляется в конец автоматически. +print("Привет, мир!") // println – теперь просто print +print("Привет, мир!", terminator: "") // вывод текста без переноса строки // переменные (var), значение которых можно изменить после инициализации // константы (let), значение которых нельзя изменить после инициализации @@ -56,12 +64,12 @@ let piText = "Pi = \(π), Pi 2 = \(π * 2)" // Вставка переменны // Сборка особых значений // используя ключ -D сборки конфигурации #if false - println("Не печатается") + print("Не печатается") let buildValue = 3 #else let buildValue = 7 #endif -println("Значение сборки: \(buildValue)") // Значение сборки: 7 +print("Значение сборки: \(buildValue)") // Значение сборки: 7 /* Опционалы - это особенность языка Swift, которая допускает вам сохранять @@ -79,31 +87,41 @@ var someOptionalString2: Optional = "опционал" if someOptionalString != nil { // я не nil if someOptionalString!.hasPrefix("opt") { - println("содержит префикс") + print("содержит префикс") } let empty = someOptionalString?.isEmpty } someOptionalString = nil +/* +Использование ! для доступа к несуществующему опциональному значению генерирует +рантайм ошибку. Всегда проверяйте, что опционал содержит не пустое значение, +перед тем как раскрывать его через !. +*/ + // неявная развертка опциональной переменной var unwrappedString: String! = "Ожидаемое значение." // как и выше, только ! - постфиксный оператор (с еще одним синтаксическим сахаром) var unwrappedString2: ImplicitlyUnwrappedOptional = "Ожидаемое значение." +// If let конструкции - +// If let это специальная конструкция в Swift, которая позволяет проверить Optional +// справа от `=` непустой, и если это так - разворачивает его и присваивает левой части. if let someOptionalStringConstant = someOptionalString { - // имеется некоторое значение, не nil + // имеется некоторое (`Some`) значение, не `nil` if !someOptionalStringConstant.hasPrefix("ok") { // нет такого префикса } } // Swift поддерживает сохранение значения любого типа +// Для этих целей есть два ключевых слова `Any` и `AnyObject` // AnyObject == id -// В отличие от `id` в Objective-C, AnyObject работает с любым значением (Class, -// Int, struct и т.д.) -var anyObjectVar: AnyObject = 7 -anyObjectVar = "Изменять значение на строку не является хорошей практикой, но возможно." +// `Any` же, в отличие от `id` в Objective-C, `Any` работает с любым значением (Class, Int, struct и т.д.) +var anyVar: Any = 7 +anyVar = "Изменять значение на строку не является хорошей практикой, но возможно." +let anyObjectVar: AnyObject = Int(1) as NSNumber /* Комментируйте здесь @@ -129,6 +147,7 @@ shoppingList[1] = "бутылка воды" let emptyArray = [String]() // let == неизменный let emptyArray2 = Array() // как и выше var emptyMutableArray = [String]() // var == изменяемый +var explicitEmptyMutableStringArray: [String] = [] // так же как и выше // Словарь @@ -140,31 +159,39 @@ occupations["Jayne"] = "Связи с общественностью" let emptyDictionary = [String: Float]() // let == неизменный let emptyDictionary2 = Dictionary() // как и выше var emptyMutableDictionary = [String: Float]() // var == изменяемый +var explicitEmptyMutableDictionary: [String: Float] = [:] // то же // // MARK: Поток управления // +// С помощью "," можно указать дополнительные условия для раскрытия +// опциональных значений. +let someNumber = Optional(7) +if let num = someNumber, num > 3 { + print("Больше 3х") +} + // цикл for для массива let myArray = [1, 1, 2, 3, 5] for value in myArray { if value == 1 { - println("Один!") + print("Один!") } else { - println("Не один!") + print("Не один!") } } // цикл for для словаря var dict = ["один": 1, "два": 2] for (key, value) in dict { - println("\(key): \(value)") + print("\(key): \(value)") } // цикл for для диапазона чисел for i in -1...shoppingList.count { - println(i) + print(i) } shoppingList[1...2] = ["бифштекс", "орехи пекан"] // используйте ..< для исключения последнего числа @@ -176,8 +203,8 @@ while i < 1000 { } // цикл do-while -do { - println("привет") +repeat { + print("привет") } while 1 == 2 // Переключатель @@ -204,7 +231,7 @@ default: // обязательный (чтобы предусмотреть вс // Функции являются типом первого класса, т.е. они могут быть вложены в функциях // и могут передаваться между собой -// Функция с документированным заголовком Swift (формат reStructedText) +// Функция с документированным заголовком Swift (формат Swift-модифицированный Markdown) /** Операция приветствия @@ -212,20 +239,20 @@ default: // обязательный (чтобы предусмотреть вс - Маркер в документировании - Еще один маркер в документации - :param: name - это имя - :param: day - это день - :returns: Строка, содержащая значения name и day. + - Parameter name : Это имя + - Parameter day : Это день + - Returns : Строка, содержащая значения name и day. */ func greet(name: String, day: String) -> String { return "Привет \(name), сегодня \(day)." } -greet("Боб", "вторник") +greet(name: "Боб", day: "вторник") // как и выше, кроме обращения параметров функции -func greet2(#requiredName: String, externalParamName localParamName: String) -> String { - return "Привет \(requiredName), сегодня \(localParamName)" +func greet2(name: String, externalParamName localParamName: String) -> String { + return "Привет \(name), сегодня \(localParamName)" } -greet2(requiredName:"Иван", externalParamName: "воскресенье") +greet2(name: "Иван", externalParamName: "Воскресенье") // Функция, которая возвращает множество элементов в кортеже func getGasPrices() -> (Double, Double, Double) { @@ -235,8 +262,31 @@ let pricesTuple = getGasPrices() let price = pricesTuple.2 // 3.79 // Пропускайте значения кортежей с помощью подчеркивания _ let (_, price1, _) = pricesTuple // price1 == 3.69 -println(price1 == pricesTuple.1) // вывод: true -println("Цена газа: \(price)") +print(price1 == pricesTuple.1) // вывод: true +print("Цена газа: \(price)") + +// Именованные параметры кортежа +func getGasPrices2() -> (lowestPrice: Double, highestPrice: Double, midPrice: Double) { + return (1.77, 37.70, 7.37) +} +let pricesTuple2 = getGasPrices2() +let price2 = pricesTuple2.lowestPrice +let (_, price3, _) = pricesTuple2 +print(pricesTuple2.highestPrice == pricesTuple2.1) // вывод: true +print("Самая высокая цена за газ: \(pricesTuple2.highestPrice)") + +// guard утверждения +func testGuard() { + // guards обеспечивают прерывание дальнейшего выполнения функции, + // позволяя держать обработчики ошибок рядом с проверкой условия + // Объявляемая переменная находится в той же области видимости, что и guard. + guard let aNumber = Optional(7) else { + return + } + + print("число равно \(aNumber)") +} +testGuard() // Переменное число аргументов func setup(numbers: Int...) { @@ -246,7 +296,7 @@ func setup(numbers: Int...) { } // Передача и возврат функций -func makeIncrementer() -> (Int -> Int) { +func makeIncrementer() -> ((Int) -> Int) { func addOne(number: Int) -> Int { return 1 + number } @@ -256,15 +306,15 @@ var increment = makeIncrementer() increment(7) // передача по ссылке -func swapTwoInts(inout a: Int, inout b: Int) { +func swapTwoInts(a: inout Int, b: inout Int) { let tempA = a a = b b = tempA } var someIntA = 7 var someIntB = 3 -swapTwoInts(&someIntA, &someIntB) -println(someIntB) // 7 +swapTwoInts(a: &someIntA, b: &someIntB) +print(someIntB) // 7 // @@ -291,13 +341,13 @@ numbers = numbers.map({ number in 3 * number }) print(numbers) // [3, 6, 18] // Хвостовое замыкание -numbers = sorted(numbers) { $0 > $1 } +numbers = numbers.sorted { $0 > $1 } print(numbers) // [18, 6, 3] // Суперсокращение, поскольку оператор < выполняет логический вывод типов -numbers = sorted(numbers, < ) +numbers = numbers.sorted(by: <) print(numbers) // [3, 6, 18] @@ -307,7 +357,7 @@ print(numbers) // [3, 6, 18] // Структуры и классы имеют очень похожие характеристики struct NamesTable { - let names = [String]() + let names: [String] // Пользовательский индекс subscript(index: Int) -> String { @@ -316,9 +366,48 @@ struct NamesTable { } // У структур автогенерируемый (неявно) инициализатор -let namesTable = NamesTable(names: ["Me", "Them"]) +let namesTable = NamesTable(names: ["Иван", "Яков"]) let name = namesTable[1] -println("Name is \(name)") // Name is Them +print("Имя :\(name)") // Имя: Яков + +// +// MARK: Обработка ошибок +// + +// Протокол `Error` используется для перехвата выбрасываемых ошибок +enum MyError: Error { + case BadValue(msg: String) + case ReallyBadValue(msg: String) +} + +// фунции помеченные словом `throws` должны вызываться с помощью `try` +func fakeFetch(value: Int) throws -> String { + guard 7 == value else { + throw MyError.ReallyBadValue(msg: "Действительно плохое значение") + } + + return "тест" +} + +func testTryStuff() { + // предполагается, что не будет выброшено никаких ошибок, + // в противном случае мы получим рантайм исключение + let _ = try! fakeFetch(value: 7) + + // Если возникает ошибка, то выполнение продолжится. Но если значение равно nil, + // то результат будет опционалом + let _ = try? fakeFetch(value: 7) + + do { + // обычно try оператор, позволяющий обработать ошибку в `catch` блоке + try fakeFetch(value: 1) + } catch MyError.BadValue(let msg) { + print("Ошибка: \(msg)") + } catch { + // все остальное + } +} +testTryStuff() // // MARK: Классы @@ -329,7 +418,7 @@ println("Name is \(name)") // Name is Them public class Shape { public func getArea() -> Int { - return 0; + return 0 } } @@ -351,6 +440,11 @@ internal class Rect: Shape { } } + // Вычисляемые свойства должны быть объявлены с помощью `var`, ведь они могут меняться + var smallestSideLength: Int { + return self.sideLength - 1 + } + // Ленивая загрузка свойства // свойство subShape остается равным nil (неинициализированным), // пока не вызовется геттер @@ -400,7 +494,7 @@ let aShape = mySquare as Shape // сравнение экземпляров, в отличие от ==, которая проверяет эквивалентность if mySquare === mySquare { - println("Ага, это mySquare") + print("Ага, это mySquare") } // Опциональная инициализация (init) @@ -423,13 +517,13 @@ class Circle: Shape { } var myCircle = Circle(radius: 1) -println(myCircle?.getArea()) // Optional(3) -println(myCircle!.getArea()) // 3 +print(myCircle?.getArea()) // Optional(3) +print(myCircle!.getArea()) // 3 var myEmptyCircle = Circle(radius: -1) -println(myEmptyCircle?.getArea()) // "nil" +print(myEmptyCircle?.getArea()) // "nil" if let circle = myEmptyCircle { // не будет выполняться, поскольку myEmptyCircle равен nil - println("circle не nil") + print("circle не nil") } @@ -456,12 +550,13 @@ enum Suit { // указывать тип перечисления, когда переменная объявляется явно var suitValue: Suit = .Hearts -// Нецелочисленные перечисления требуют прямого указания значений +// Значения нецелочисленных перечислений должны быть указаны явно +// или могут выводится с помощью функции `rawValue` из имени enum BookName: String { - case John = "Иоанн" + case John case Luke = "Лука" } -println("Имя: \(BookName.John.rawValue)") +print("Имя: \(BookName.John.rawValue)") // Перечисление (enum) со связанными значениями enum Furniture { @@ -481,9 +576,9 @@ enum Furniture { } var desk: Furniture = .Desk(height: 80) -println(desk.description()) // "Письменный стол высотой 80 см." +print(desk.description()) // "Письменный стол высотой 80 см." var chair = Furniture.Chair("Foo", 40) -println(chair.description()) // "Стул марки Foo высотой 40 см." +print(chair.description()) // "Стул марки Foo высотой 40 см." // @@ -500,10 +595,10 @@ protocol ShapeGenerator { } // Протоколы, объявленные с @objc, допускают необязательные функции, -// которые позволяют вам проверять на соответствие +// которые позволяют вам проверять на соответствие. Для функций также необходимо указать @objc @objc protocol TransformShape { - optional func reshaped() - optional func canReshape() -> Bool + @objc optional func reshape() + @objc optional func canReshape() -> Bool } class MyShape: Rect { @@ -511,12 +606,13 @@ class MyShape: Rect { func grow() { sideLength += 2 + // Размещайте знак вопроса перед опционным свойством, методом // или индексом, чтобы не учитывать nil-значение и возвратить nil // вместо выбрасывания ошибки выполнения (т.н. "опционная цепочка") - if let allow = self.delegate?.canReshape?() { + if let reshape = self.delegate?.canReshape?(), reshape { // проверка делегата на выполнение метода - self.delegate?.reshaped?() + self.delegate?.reshape?() } } } @@ -528,14 +624,14 @@ class MyShape: Rect { // `extension`s: Добавляет расширенный функционал к существующему типу -// Класс Square теперь "соответствует" протоколу `Printable` -extension Square: Printable { +// Класс Square теперь "соответствует" протоколу `CustomStringConvertible` +extension Square: CustomStringConvertible { var description: String { return "Площадь: \(self.getArea()) - ID: \(self.identifier)" } } -println("Объект Square: \(mySquare)") +print("Объект Square: \(mySquare)") // Вы также можете расширить встроенные типы extension Int { @@ -548,22 +644,22 @@ extension Int { } } -println(7.customProperty) // "Это 7" -println(14.multiplyBy(3)) // 42 +print(7.customProperty) // "Это 7" +print(14.multiplyBy(num: 3)) // 42 // Обобщения: Подобно языкам Java и C#. Используйте ключевое слово `where`, // чтобы определить условия обобщений. func findIndex(array: [T], valueToFind: T) -> Int? { - for (index, value) in enumerate(array) { + for (index, value) in array.enumerated() { if value == valueToFind { return index } } return nil } -let foundAtIndex = findIndex([1, 2, 3, 4], 3) -println(foundAtIndex == 2) // вывод: true +let foundAtIndex = findIndex(array: [1, 2, 3, 4], valueToFind: 3) +print(foundAtIndex == 2) // вывод: true // Операторы: // Пользовательские операторы могут начинаться с символов: @@ -571,19 +667,33 @@ println(foundAtIndex == 2) // вывод: true // или // Unicode- знаков математики, символов, стрелок, декорации и линий/кубов, // нарисованных символов. -prefix operator !!! {} +prefix operator !!! // Префиксный оператор, который утраивает длину стороны, когда используется -prefix func !!! (inout shape: Square) -> Square { +prefix func !!! (shape: inout Square) -> Square { shape.sideLength *= 3 return shape } // текущее значение -println(mySquare.sideLength) // 4 +print(mySquare.sideLength) // 4 // Используя пользовательский оператор !!!, изменится длина стороны // путем увеличения размера в 3 раза !!!mySquare -println(mySquare.sideLength) // 12 +print(mySquare.sideLength) // 12 + +// Операторы также могут быть обобщенными +infix operator <-> +func <-> (a: inout T, b: inout T) { + let c = a + a = b + b = c +} + +var foo: Float = 10 +var bar: Float = 20 + +foo <-> bar +print("foo это \(foo), bar это \(bar)") // "foo = 20.0, bar = 10.0" ```