Содержание

SWIFT — что это простыми словами?

Ежедневно совершается масса денежных переводов между различными странами, обеспечивая стабильность бизнес-процессов и взаимодействие между организациями. Развитие технологий сделало SWIFT-перевод максимально удобным и простым, позволяя доставлять деньги по всему миру в кратчайшие сроки. Чтобы пользоваться международными переводами, необходимо разобраться в предназначении и особенностях SWIFT-системы: что это такое и каков порядок осуществления транзакций.

Межбанковская система SWIFT с высокой точностью и минимальной комиссией осуществляет переводы, оплату счетов. Для отправки платежа потребуется точное указание реквизитов счета, получателя. Ввиду того, что в каждой транзакции может быть задействовано несколько посреднических структур, некорректные реквизиты могут привести к тому, что деньги зависают в системе на счету какого-либо банка-корреспондента.

Как расшифровывается SWIFT?

С помощью системы SWIFT организации и частные лица могут переводить друг другу деньги в любой требуемой валюте на выгодных и комфортных условиях.

Созданная в 1973 году, система СВИФТ объединила большое количество ведущих банков Америки и Европы. Число финансовых организаций, задействованных в системе СВИФТ на этапе создания, сразу превысило две сотни банков. Целью объединения в единую платежную систему послужило желание быстро и безопасно передавать средства от одного банка другому вне зависимости от границ между странами и других препятствий.

Головная организация размещена в Бельгии, а число входящих организаций уже более 10 тысяч. Система позволяет обслуживать клиент

Язык программирования Swift. Русская версия / Блог компании Apphud / Хабр

Привет, Хабр! 2 июня все мы воочию могли наблюдать, как компания Apple начала творить революцию в стане Objective-C разработчиков, представив миру свой новый язык программирования – Swift. Вместе с этим, она выложила в открытый доступ небольшую документацию по языку, которую мы решили перевести, если на то будет спрос. Предлагаем вашему вниманию перевод первой главы. Если тема будет интересна, то мы продолжим публиковать перевод каждую неделю.
Оглавление

Добро пожаловать в Swift
    О Swift
    Введение в Swift

Language guide
    The Basics
    Basic Operators
    String and Characters

    Collection Types
    Control Flow
    Functions
    Closures
    Enumerations
    Classes and Structures
    Properties
    Methods
    Subscripts
    Inheritance
    Initialization
    Deinitialization
    Automatic Reference Counting
    Optional Chaining
    Type Casting
    Nested Types
    Extensions
    Protocols
    Generics
    Advanced Operators

Language Reference
    About the Language Reference
    Lexical Structure
    Types
    Expressions
    Statements
    Declarations
    Attributes
    Patterns
    Generic Parameters and Arguments
    Summary of the Grammar
    Trademarks

Добро пожаловать в Swift

О языке Swift

Swift – это новый язык программирования для разработки iOS и OS X приложений, который сочетает в себе все лучшее от C и Objective-C, но лишен ограничений, накладываемых в угоду совместимости с C. В Swift используются паттерны безопасного программирования и добавлены современные функции, превращающие создание приложения в простой, более гибкий и увлекательный процесс. Swift, созданый нами с чистого листа, – это возможность заново представить себе, как разрабатываются приложения.

Swift разрабатывался нами несколько лет. Основой нового языка программирования послужили существующие компилятор, отладчик и фреймворки. Мы упростили процесс управления памятью с помощью механизма автоматического подсчета ссылок – Automatic Reference Counting (ARC). Наши фреймворки также подверглись серьезной модернизации. Objective-C начал поддерживать блоки, литералы и модули – все это создало благоприятные условия для внедрения современных технологий. Именно эта подготовительная работа послужила фундаментом для нового языка программирования, который будет применяться для разработки будущих программных продуктов для Apple.

Разработчикам Objective-C Swift покажется знакомым. Он сочетает в себе читабельность именованных параметров и мощь динамической объектной модели Objective-C. Он открывает доступ к уже существующим фреймворкам Cocoa и совместим с кодом, написанным на Objective-C. Построенный на этой общей основе язык предлагает множество новых возможностей и унифицирует процедурные и объектно-ориентированные аспекты языка программирования.

Swift не отпугнет и начинающих программистов. Это первый мощный язык программирования, такой же понятный и увлекательный, как скриптовый язык. Он поддерживает так называемые playground-ы, которые позволяют программистам экспериментировать с кодом, видя результат в режиме реального времени без необходимости компилировать и запускать приложение.

Swift вобрал в себя все лучшее от современных языков и разработан с учетом обширного опыта компании Apple. Наш компилятор – синоним производительности, наш язык оптимизирован для разработки без оглядки на компромиссы. Он спроектирован таким образом, чтобы вы смогли легко разработать и ваше первое приложение «hello, world!», и даже целую операционную систему. Все это делает Swift важным инструментом для разработчиков и для самой компании Apple.

Swift – это новый фантастический способ создавать приложения для iOS и OS X, и мы продолжим развивать его, добавляя новый функционал и представляя новые возможности. Наша цель – амбициозна. И мы с нетерпением ждем, чтобы увидеть, что вы сумеете создать при помощи него.

Введение в Swift

По давней традиции первая программа на новом языке должна выводить на экран слова “Hello, world”. С помощью Swift это делается так:
println("Hello, world")

Если вы когда-нибудь разрабатывали на C или Objective-C этот синтаксис должен казаться вам до боли знакомым – в Swift эта строчка кода является законченной программой. Вам больше не нужно импортировать отдельные библиотеки для обеспечения базового функционала вроде ввода/вывода в консоль или работы со строками. Код, написанный в глобальной области видимости, является точкой входа в программу, таким образом функция main больше не нужна. Также обратите внимание на отсутствие точки с запятой в конце каждой строки.

Это введение содержит достаточно информации, чтобы начать писать код на Swift. Не переживайте, если вам будет что-то непонятно – мы все детально объясним в последующих главах.

Замечание
Для лучшего понимания материала мы рекомендуем использовать режим playground в Xcode. Playground позволяет вам видеть результат сразу в процессе редактирования кода без необходимости компилировать и запускать приложение.

Простые типы данных

Используйте let для создания константы и var для создания переменной. Тип константы указывать не нужно, вы можете присвоить ей значение лишь единожды.
var myVariable = 42
myVariable = 50
let myConstant = 42

Типы константы и переменной должны совпадать с типами присваиваемых им соответствующих значений. Однако это не означает, что вы должны напрямую указывать их тип. Компилятор автоматически определит тип константы и переменной при присваивании им значения. Так, в приведенном примере компилятор определит, что myVariable имеет целочисленный тип.

Если же инициализатор отсутствует или не предоставляет достаточной информации, вы можете указать тип самостоятельно после переменной, разделив название и тип двоеточием:

let implicitInteger = 70
let inplicitDouble = 70.0
let inplicitDouble: 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 = "I have \(apples + oranges) pieces of fruit."

Давайте поэкспериментируем
Попробуйте использовать конструкцию \() и выведите на экран строку, включающую результат суммы двух целочисленных переменных и чье-нибудь имя.

При работе с массивами и ассоциативными массивами (словарями, dictionary) используются квадратные скобки ([]):
var shoppingList = ["catfish", "water", "tulips", "blue paint"]
shoppingList[1] = "bottle of water"
 
var occupations = [
    "Malcolm": "Captain",
    "Kaylee": "Mechanic",
]
occupations["Jayne"] = "Public Relations"

Чтобы создать пустой массив или dictionary, используйте следующий синтаксис:
let emptyArray = String[]()
let emptyDictionary = Dictionary<String, Float>()

Для создания пустых массивов и словарей используйте [] и [:] соответственно, – например, когда вы присваиваете новое значение переменной или передаете аргумент в функцию.
shoppingList = []   // Went shopping and bought everything.
Условия и циклы

Для создания условий используются операторы 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 должно быть логическим, это в частности означает, что выражение
if score {…}
является ошибочным, поскольку здесь нет явного сравнения (например, с нулем).

Условный оператор if можно использовать совместно с let и var для работы с константами и переменными, которые могут иметь значение nil. Такие константы и переменные называются опциональными (то есть они могут либо принимать какое-либо значение, либо быть равны 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, условие будет ложным и код в фигурных скобках после if выполнен не будет. В противном случае переменной
greeting
будет присвоено новое значение.

Оператор множественного выбора 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."
}

Давайте поэкспериментируем
Попробуйте удалить условие по умолчанию. Какую ошибку вы получите?

После выполнения подходящего блока кода, программа покидает оператор switch, не проверяя последующие условия. Таким образом вам не нужно вручную добавлять операторы прерывания (break) в конце каждого блока case.

Для перебирания элементов ассоциативного массива используйте оператор 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 позволяет выполнять блок кода внутри него до тех пор, пока условие не станет ложным. Условие также может быть указано после блока, который в таком случае будет выполнен по крайней мере один раз.
var n = 2
while n < 100 {
    n = n * 2
}
n
 
var m = 2
do {
    m = m * 2
} while m < 100
m

Оператор for можно использовать для перебора последовательности чисел с помощью двух точек (..) или с помощью инициализатора, условия и инкремента. Посмотрите, эти два цикла делают одно и то же:
var firstForLoop = 0
for i in 0..3 {
    firstForLoop += i
}
firstForLoop
 
var secondForLoop = 0
for var i = 0; i < 3; ++i {
    secondForLoop += 1
}
secondForLoop

При создании цикла используйте две точки (..), если не хотите включать большее значение в диапазон, и три точки (), чтобы включить как меньшее, так и большее значения.
Функции и замыкания.

Для объявления функций используйте ключевое слово func. Вызов функции производится через указание ее имени и списка аргументов в круглых скобках. Возвращаемый тип следует отделить от перечня формальных аргументов с помощью ->.
func greet(name: String, day: String) -> String {
    return "Hello \(name), today is \(day)."
}
greet("Bob", "Tuesday")

Давайте поэкспериментируем
Удалите параметр day. Вместо него добавьте переменную, обозначающую наименование подаваемого на обед блюда.

Если функция возвращает множество значений, следует использовать кортеж:
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()

Функции являются объектами первого класса (first-class type), иными словами, функция в качестве свого результата может возвращать другую функцию.
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
    })

Давайте поэкспериментируем
Перепишите замыкание таким образом, чтобы оно возвращало ноль для всех лишних чисел.

Существует несколько техник, позволяющих делать замыкания более лаконичными. Если тип замыкания априори известен (например, это 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."
    }
}

Давайте поэкспериментируем
Добавьте константу-член класса и метод класса, принимающую ее в качестве своего аргумента.

Чтобы создать экземпляр (объект) класса, достаточно добавить круглые скобки после названия класса. Доступ к методам и членам класса осуществляется через точку.
var shape = Shape()
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()

В этом примере мы упустили одну важную деталь – конструктор класса, метод 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."
    }
}

Обратите внимание, как член класса name при помощи self отделен от аргумента конструктора name. Аргументы передаются в конструктор обычным образом, как и в любой другой метод класса. Обратите внимание на то, что каждый член класса должен быть проинициализирован – либо при объявлении (как, например, numberOfSides), либо в конструкторе (как name).

Деструктор класса – метод deinit, который можно переписать в случае необходимости.

Чтобы наследовать класс от уже существующего класса, после указания имени дочернего класса следует поставить двоеточие и указать название родительского. В Swift нет никаких ограничений по обязательному наследованию какого-либо стандартного класса.

Переопределенные дочерним классом методы должны быть помечены ключевым словом override – переопределение методов без 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 \(sideLength)."
    }
}
let test = Square(sideLength: 5.2, name: "my test square")
test.area()
test.simpleDescription()

Давайте поэкспериментируем
Создайте класс Circle и наследуйте его от класса NamedShape. Конструктор класса Circle принимает два аргумента – радиус и название. Переопределите методы area и describe этого класса.

Члены класса могут также иметь собственные 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 triagle with sides of length \(sideLength)."
    }
}
var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
triangle.perimeter
triangle.perimeter = 9.9
triangle.sideLength

В setter-е переменной perimeter новое присваиваемое значение неявно называется newValue. Вы можете изменить название этой переменной, указав его в скобках сразу после set.

Обратите внимание на структуру конструктора класса EquilateralTriangle. Этот метод включает в себя три последовательных шага:

  1. инициализация членов дочернего класса;
  2. вызов конструктора родительского класса;
  3. изменение значений членов родительского класса.

Если вам необходимо выполнить определенный код до или после присваивания нового значения переменной, вы можете переопределить методы 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

У методов классов имеется одно важное отличие от функций. Названия аргументов функции используются только в пределах этой функции, тогда как в методе класса параметры также используются при вызове этого метода (кроме первого параметра). По умолчанию метод класса имеет одинаковые названия параметров как при вызове, так и внутри себя. Однако вы можете указать другое название (в примере ниже – times), которое будет использовано только внутри этого метода. При этом для вызова этого метода необходимо использовать первое название (numberOfTimes).
class Counter {
    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
Перечисления и Структуры

Для создания перечислений используется ключевое слово enum. Отметим, что перечисления также могут иметь в своем составе методы.
enum Rank: Int {
    case Ace = 1
    case Two, Three, Four, Five, Six, Seven, Eight, 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()

Давайте поэкспериментируем
Напишите функцию, которая сравнивает 2 перечисления типа Rank по их значениям.

В вышеприведенном примере элементы перечисления первоначально имеют целочисленный тип, и вам достаточно указать значение только первого элемента – значения остальных элементов будут определены в соответствии с порядком их следования. В качестве исходного типа (raw value) значений элементов вы также можете выбрать строковый или вещественные типы.

Для преобразования исходного типа значения в тип перечисления используйте функции 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 "hearts"
        case .Diamonds:
            return "diamonds"
        case .Clubs:
            return "clubs"
        }
    }
}
let hearts = Suit.Hearts
let heartsDescription = hearts.simpleDescription()

Давайте поэкспериментируем
Добавьте метод Color, возвращающий строку “black” для Spades и Clubs и “red” для Hearts и Diamonds.

Обратите внимание на то, как осуществляется доступ к члену Hearts перечисления Suit. При присваивании значения константе hearts используется полное имя Suit.Hearts, поскольку мы явно не указываем тип этой константы. А в switch мы используем сокращенную форму .Hearts, поскольку тип значения self априори известен. Вы можете использовать сокращенную форму повсеместно, если тип переменной явно указан.

Для создания структур используется ключевое слово struct. Структуры имеют множество схожих черт с классами, включая методы и конструкторы. Одним из наиболее существенных отличий структур от классов является то, что экземпляры структур, в отличие от экземпляров классов, передаются в функции по значению (то есть предварительно создается их локальная копия), тогда как экземпляры классов передаются по ссылке.

struct Card {
    var rank: Rank
    var suit: Suit
    func simpleDescription() -> String {
        return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
    }
}
let threeOfSpades = Card(rank: .Three, suit: .Spades)
let threeOfSpadesDescription = threeOfSpades.simpleDescription()

Давайте поэкспериментируем
Добавьте в структуру Card метод, который создает полную колоду карт.

Экземпляр члена перечисления может иметь собственные значения и они могут быть разными. Вы присваиваете эти значения при создании экземпляра перечисления (константа success в примере). Связанные и исходные значения это разные вещи: исходное значение члена перечисления всегда постоянно для всех экземпляров перечисления и указывается при его объявлении.

Рассмотрим пример получения с сервера времени восхода и заката Солнца. Сервер отправляет в ответ либо соответствующую информацию, либо сообщение об ошибке.

enum ServerResponse {
    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)"
}

Давайте поэкспериментируем
Добавьте третий вариант в оператор множественного выбора switch

Обратите внимание, каким образом из объекта ServerResponse “вытаскиваются” время восхода и заката.
Протоколы и Расширения.

Для объявления протокола используйте ключевое слово protocol.
protocol ExampleProtocol {
    var simpleDescription: String { get }
    mutating func adjust()
}

Протоколы могут поддерживаться классами, перечислениями и структурами.
class SimpleClass: ExampleProtocol {
    var simpleDescription: String = "A very simple class."
    var anotherProperty: Int = 69105
    func adjust() {
        simpleDescription += "  Now 100% adjusted."
    }
}
var a = SimpleClass()
a.adjust()
let aDescription = a.simpleDescription
 
struct SimpleStructure: ExampleProtocol {
    var simpleDescription: String = "A simple structure"
    mutating func adjust() {
        simpleDescription += " (adjusted)"
    }
}
var b = SimpleStructure()
b.adjust()
let bDescription = b.simpleDescription

Давайте поэкспериментируем
Создайте перечисление, которое будет реализовывать этот протокол.

Обратите внимание на ключевое слово mutating в определении структуры SimpleStructure, которое информирует компилятор о том, что соответствующий метод подвергает структуру изменениям. В противовес этому методы класса SimpleClass не нужно маркировать как mutating, поскольку методы класса всегда могут беспрепятственно его изменять.

Для добавления новых методов или членов класса в уже существующий тип необходимо использовать расширения – extensions. Вы также можете использовать расширения для реализации протокола уже существующим типом, даже если он импортирован из какой-либо библиотеки или фреймворка.

extension Int: ExampleProtocol {
    var simpleDescription: String {
    return "The number \(self)"
    }
    mutating func adjust() {
        self += 42
    }
}
7.simpleDescription

Давайте поэкспериментируем
Создайте расширение типа Double с переменной-членом absoluteValue.

Вы можете использовать название протокола как и любой другой тип – например, чтобы создать массив объектов разного типа, но реализующих общий протокол. Заметьте, что при работе с объектами такого типа методы, объявленные вне протокола, будут недоступны.
let protocolValue: ExampleProtocol = a
protocolValue.simpleDescription
// protocolValue.anotherProperty  // Uncomment to see the error

Несмотря на то, что во время выполнения программы переменная protocolValue имеет тип SimpleClass, компилятор считает, что ее тип – ExampleProtocol. Это означает, что вы не сможете случайно получить доступ к методам или членам класса, которые реализуются вне протокола ExampleProtocol.
Обобщенные типы (generics)

Для создания обобщенного типа, заключите имя в угловые скобки (<>).
func repeat<ItemType>(item: ItemType, times: Int) -> ItemType[] {
    var result = ItemType[]()
    for i in 0..times {
        result += item
    }
    return result
}
repeat("knock", 4)

Создавайте обобщенные функции, классы, перечисления и структуры.
// Reimplement the Swift standard library's optional type
enum OptionalValue<T> {
    case None
    case Some(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>.
Хотите внедрить подписки в iOS-приложение за 10 минут? Интегрируйте Apphud и:
— оформляйте покупки с помощью лишь одного метода;
— автоматически отслеживайте состояние подписки каждого пользователя;
— легко интегрируйте Subscription Offers;
— отправляйте события о подписках в Amplitude, Mixpanel, Slack и Telegram с учетом локальной валюты пользователя;
— уменьшайте Churn rate в приложениях и возвращайте отписавшихся пользователей.

Swift. Вопросы и ответы / Хабр

Языку программирования Swift всего четыре года, но он уже становится основным языком разработки для iOS. Развиваясь до версии 5.0, Swift превратился в сложный и мощный язык, отвечающий как объектно-ориентированной, так и функциональной парадигме. И с каждым новым релизом в нем добавляется еще больше возможностей.

Но насколько хорошо вы на самом деле знаете Swift? В этой статье вы найдете примеры вопросов для собеседования по Swift.

Вы можете использовать эти вопросы для интервьюирования кандидатов, чтобы проверить их знания или вы можете проверить свои собственные. Если вы не знаете ответа, не переживайте: к каждому вопросу есть ответ.

Вопросы разделены на три группы:

  • Beginner: для начинающих. Вы прочитали пару книг и применяли Swift в своих собственных приложениях.
  • Intermediate: подходят для тех, кто действительно заинтересовался языком. Вы уже достаточно много прочитали о нём и часто экспериментируете.
  • Advanced: подходят для самых продвинутых разработчиков — тех, кому нравится влезать в дебри синтаксиса и использовать передовые приёмы.

Для каждого уровня есть два типа вопросов:
  • письменные: подойдут для тестирования по email, так как предполагают написание кода.
  • устные: можно использовать при беседе по телефону или при личном контакте, так как тут достаточно ответа словами.

Читая статью, держите открытым playground, чтобы иметь возможность проверить код из вопроса. Все ответы были протестированы на Xcode 10.2 и Swift 5.
  • Beginner


    письменные вопросыВопрос 1Рассмотрим следующий код:
    struct Tutorial {
      var difficulty: Int = 1
    }
    
    var tutorial1 = Tutorial()
    var tutorial2 = tutorial1
    tutorial2.difficulty = 2

    Чему равны значения tutorial1.difficulty и tutorial2.difficulty? Была бы какая-то разница, если бы Tutorial был классом? Почему?ответtutorial1.difficulty равен 1, а tutorial2.difficulty равен 2.

    В Swift структуры — типы-значения (value type). Они копируются, а не ссылаются. Следующая строка копирует tutorial1 и присваивает её tutorial2:

    var tutorial2 = tutorial1

    Изменения в tutorial2 не отражаются на tutorial1.

    Если бы Tutorial был бы классом, tutorial1.difficulty и tutorial2.difficulty равнялись бы 2. Классы в Swift — ссылочные типы (reference type). Когда вы меняете свойство tutorial1, вы увидите такое же изменение у tutorial2 — и наоборот.



    Вопрос 2Вы объявили view1 при помощи var, а view2 — при помощи let. В чём разница и скомпилируется ли последняя строка?
    import UIKit
    
    var view1 = UIView()
    view1.alpha = 0.5
    
    let view2 = UIView()
    view2.alpha = 0.5 // Эта строка скомпилируется?

    ответДа, последняя строка скомпилируется. view1 — это переменная, и вы можете назначить её значение новым экземпляром UIView. Используя let, вы можете присвоить значение лишь однажды, так что следующий код не скомпилируется:
    view2 = view1 // Ошибка: view2 is immutable

    Однако, UIView — это класс со ссылочной семантикой, так что вы можете изменять свойства view2 — что означает, что код скомпилируется.
    Вопрос 3Этот код сортирует массив по алфавиту. Максимально упростите замыкание.
    var animals = ["fish", "cat", "chicken", "dog"]
    animals.sort { (one: String, two: String) -> Bool in
        return one < two
    }
    print(animals)

    ответSwift автоматически определяет тип параметров замыкания и возвращаемый тип, так что вы можете убрать их:
    animals.sort { (one, two) in return one < two }

    Вы можете заменить имена параметров использованием нотации $i:
    animals.sort { return $0 < $1 }

    Замыкания, состоящие из одного оператора, могут не содержать ключевое слово return. Значение последнего выполненного оператора становится возвращаемым результатом замыкания:
    animals.sort { $0 < $1 }

    Наконец, так как Swift знает, что элементы массива соответствуют протоколу Equatable, вы можете просто написать:
    animals.sort(by: <)

    Upd: hummingbirddj упростил ещё больше:

    В данном случае можно еще короче:
     animals.sort()
    – сортирует по возрастанию, работает для типов, реализующих Comparable.


    Вопрос 4Этот код создаёт два класса: Address и Person. Также создаются два экземпляра класса Person (Ray и Brian).
    class Address {
      var fullAddress: String
      var city: String
      
      init(fullAddress: String, city: String) {
        self.fullAddress = fullAddress
        self.city = city
      }
    }
    
    class Person {
      var name: String
      var address: Address
      
      init(name: String, address: Address) {
        self.name = name
        self.address = address
      }
    }
    
    var headquarters = Address(fullAddress: "123 Tutorial Street", city: "Appletown")
    var ray = Person(name: "Ray", address: headquarters)
    var brian = Person(name: "Brian", address: headquarters)

    Предположим, что Brian переехал по новому адресу и вы хотите обновить его запись следующим образом:
    brian.address.fullAddress = "148 Tutorial Street"

    Это компилируется и выполняется без ошибок. Но, если вы проверите теперь адрес Ray, то вы увидите, что он тоже «переехал».

    Что здесь произошло и как мы можем исправить это?

    ответ

    Address — это класс и обладает ссылочной семантикой. Таким образом, headquarters — это один и тот же экземпляр класса, который разделяют ray и brian. Изменение headquarters изменит адрес обоих.
    Чтобы исправить это, можно создать новый экземпляр класса Address и присвоить его Brian, или объявить Address как struct вместо class.


    устные вопросыВопрос 1Что такое optional и какие проблемы они решают?ответ

    optional позволяет переменной любого типа представить ситуацию "отсутствие значения". В Objective-C «отсутствие значения» было доступно только в ссылочных типах с использованием специального значения nil. У типов-значений (value types), вроде int или float, такой возможности не было.
    Swift расширил концепцию «отсутствия значения» на типы-значения. Переменная optional может содержать либо значение, либо nil, сигнализирующее об отсутствии значения.



    Вопрос 2Коротко перечислите основные отличия между structure и class.ответ

    Классы поддерживают наследование, а структуры — нет.
    Классы — ссылочный тип, структуры — тип-значение.



    Вопрос 3Что такое generics и для чего они нужны?ответВ Swift вы можете использовать generics в классах, структурах и перечислениях.

    Generics устраняют проблему дублирования кода. Если у вас есть метод, который принимает параметры одного типа, иногда приходится дублировать код, чтобы работать с параметрами другого типа.

    Например, в этом коде вторая функция — это «клон» первой, за исключением того, что у неё параметры string, а не integer.

    func areIntEqual(_ x: Int, _ y: Int) -> Bool {
      return x == y
    }
    
    func areStringsEqual(_ x: String, _ y: String) -> Bool {
      return x == y
    }
    
    areStringsEqual("ray", "ray") // true
    areIntEqual(1, 1) // true

    Применяя generics, вы совмещаете две функции в одной и одновременно обеспечиваете безопасность типов:
    func areTheyEqual<T: Equatable>(_ x: T, _ y: T) -> Bool {
      return x == y
    }
    
    areTheyEqual("ray", "ray")
    areTheyEqual(1, 1)

    Так как вы тестируете равенство, вы ограничиваете типы теми, которые отвечают протоколу Equatable. Этот код обеспечивает требуемый результат и препятствует передаче параметров неподходящего типа.


    Вопрос 4В некоторых случаях не получится избежать неявного разворачивания (implicitly unwrapped) optionals. Когда и почему?ответНаиболее частые причины для использования implicitly unwrapped optionals:
    • когда вы не можете инициализировать свойство, которое не nil в момент создания. Типичный пример — outlet у Interface Builder, который всегда инициализируется после его владельца. В этом особенном случае, если в Interface Builder всё правильно сконфигурировано — вам гарантировано, что outlet не-nil перед его использованием.
    • чтобы разрешить проблему цикла сильных ссылок, когда два экземпляра классов ссылаются друг на друга и требуется не-nil ссылка на другой экземпляр. В этом случае вы помечаете ссылку на одной стороне как unowned, а на другой стороне используете неявное разворачивание optional.


    Вопрос 5Какими способами можно развернуть optional? Оцените их в смысле безопасности.
    var x : String? = "Test"

    Подсказка: всего 7 способов.

    ответПринудительное развёртывание (forced unwrapping) — небезопасно.
    let a: String = x!

    Неявное развертывание при объявлении переменной — небезопасно.
    var a = x!

    Optional binding — безопасно.
    if let a = x {
      print("x was successfully unwrapped and is = \(a)")
    }

    Optional chaining — безопасно.
    let a = x?.count

    Nil coalescing operator — безопасно.
    let a = x ?? ""

    Оператор Guard — безопасно.
    guard let a = x else {
      return
    }

    Optional pattern — безопасно.
    if case let a? = x {
      print(a)
    }




  • Intermediate


    письменные вопросыВопрос 1В чём разница между nil и .none?ответНет никакой разницы, Optional.none (кратко .none) и nil эквивалентны.
    Фактически, следующий оператор вернёт true:
    nil == .none

    Использование nil более общепринято и рекомендовано.



    Вопрос 2Здесь модель термометра в виде класса и структуры. Компилятор жалуется на последнюю строчку. Что там не так?
    public class ThermometerClass {
      private(set) var temperature: Double = 0.0
      public func registerTemperature(_ temperature: Double) {
        self.temperature = temperature
      }
    }
    
    let thermometerClass = ThermometerClass()
    thermometerClass.registerTemperature(56.0)
    
    public struct ThermometerStruct {
      private(set) var temperature: Double = 0.0
      public mutating func registerTemperature(_ temperature: Double) {
        self.temperature = temperature
      }
    }
    
    let thermometerStruct = ThermometerStruct()
    thermometerStruct.registerTemperature(56.0)
    

    ответThermometerStruct корректно объявлен с mutating функцией для изменения внутренней переменной. Компилятор жалуется на то, что вы вызываете метод registerTemperature экземпляра, который был создан при помощи let, таким образом, этот экземпляр неизменяемый (immutable). Изменение let на var исправит ошибку компиляции.

    В структурах вы должны помечать методы, которые изменяют внутренние переменные, как mutating, но вы не можете вызывать эти методы, используя immutable экземпляр.



    Вопрос 3Что выведет этот код и почему?
    var thing = "cars"
    
    let closure = { [thing] in
      print("I love \(thing)")
    }
    
    thing = "airplanes"
    
    closure()
    ответБудет напечатано: I love cars. Список захвата создаст копию переменной в момент объявления замыкания. Это означает, что захваченная переменная не изменит своего значения, даже после присвоения нового значения.

    Если вы опустите список захвата в замыкании, то компилятор будет использовать ссылку, а не копию. Вызов замыкания отразит изменение в переменной:

    var thing = "cars"
    
    let closure = {    
      print("I love \(thing)")
    }
    
    thing = "airplanes"
    
    closure() // Prints: "I love airplanes"



    Вопрос 4Это функция, которая считает количество уникальных значений в массиве:
    func countUniques<T: Comparable>(_ array: Array<T>) -> Int {
      let sorted = array.sorted()
      let initial: (T?, Int) = (.none, 0)
      let reduced = sorted.reduce(initial) {
        ($1, $0.0 == $1 ? $0.1 : $0.1 + 1)
      }
      return reduced.1
    }

    Она использует sorted, так что она использует только типы, соответствующие протоколу Comparable.

    Вы можете вызвать ее так:

    countUniques([1, 2, 3, 3]) // результат 3

    Перепишите эту функцию как расширение Array, чтобы можно было использовать так:

    [1, 2, 3, 3].countUniques() // должна вывести 3
    примечание переводчикаЧто-то уж больно монструозная функция. Почему бы не так:
    func countUniques<T: Hashable>(_ array: Array<T>) -> Int {
        return Set(array).count
    }


    ответ
    extension Array where Element: Comparable {
      func countUniques() -> Int {
        let sortedValues = sorted()
        let initial: (Element?, Int) = (.none, 0)
        let reduced = sortedValues.reduce(initial) { 
          ($1, $0.0 == $1 ? $0.1 : $0.1 + 1) 
        }
        return reduced.1
      }
    }



    Вопрос 5Вот функция, которая делит два optional doubles. Есть три условия, которые должны соблюдаться:
    • делимое не должно быть nil
    • делитель не должен быть nil
    • делитель не должен быть равен 0
    func divide(_ dividend: Double?, by divisor: Double?) -> Double? {
      if dividend == nil {
        return nil
      }
      if divisor == nil {
        return nil
      }
      if divisor == 0 {
        return nil
      }
      return dividend! / divisor!
    }

    Перепишите эту функцию, используя оператор guard и не используя принудительное развёртывание (forced unwrapping).
    ответОператор guard, появившийся в Swift 2.0, обеспечивает выход в случае не соблюдения условия. Вот пример:
    guard dividend != nil else { return nil }

    Вы также можете использовать оператор guard для optional binding, после чего развернутая переменная будет доступна и за пределами оператора guard:

    guard let dividend = dividend else { return .none }

    Таким образом, вы можете переписать функцию так:

    func divide(_ dividend: Double?, by divisor: Double?) -> Double? {
      guard let dividend = dividend else { return nil }
      guard let divisor = divisor else { return nil }
      guard divisor != 0 else { return nil }
      return dividend / divisor
    }

    Обратите внимание на отсутствие принудительной распаковки, так как мы уже распаковали делимое и делитель и поместили их в non-optional immutable переменные.

    Обратите также внимание на то, что результат распакованных optionals в операторе guard доступен и за пределами оператора guard.

    Вы можете еще больше упростить функцию путем группировки операторов guard:

    func divide(_ dividend: Double?, by divisor: Double?) -> Double? {
      guard 
        let dividend = dividend,
        let divisor = divisor,
        divisor != 0 
        else { 
          return nil 
        }
      return dividend / divisor
    }



    Вопрос 6Перепишите метод из вопроса 5 с использованием оператора if let.ответОператор if let позволяет вам распаковывать optionals и использовать это значение внутри этого блока кода. Вне его эти значения будут недоступны.
    func divide(_ dividend: Double?, by divisor: Double?) -> Double? {
      if 
        let dividend = dividend,
        let divisor = divisor,
        divisor != 0 {
          return dividend / divisor
      } else {
        return nil
      }
    }




    устные вопросыВопрос 1В Objective-C вы объявляете константу таким образом:
    const int number = 0;

    А так в Swift:
    let number = 0

    В чём тут разница?ответВ Objective-C константа инициализируется во время компиляции значением, которое должно быть известно на этом этапе.

    Неизменяемое значение, созданное при помощи let — это константа, определяемая на этапе выполнения. Вы можете инициализировать ее статическим или динамическим выражением. Поэтому мы можем делать так:

    let higherNumber = number + 5

    Обратите внимание: такое присвоение возможно сделать лишь однажды.



    Вопрос 2Чтобы объявить статическое свойство или функцию для типов-значений, используется модификатор static. Вот пример для структуры:
    struct Sun {
      static func illuminate() {}
    }
    

    А для классов возможно использовать модификаторы static или class. Результат один и тот же, но есть отличие. Опишите его.ответstatic делает свойство или функцию статической и неперекрываемой. Использование class позволит перекрыть свойство или функцию.

    Здесь компилятор будет ругаться на попытку перекрыть illuminate():

    class Star {
      class func spin() {}
      static func illuminate() {}
    }
    class Sun : Star {
      override class func spin() {
        super.spin()
      }
      // error: class method overrides a 'final' class method
      override static func illuminate() { 
        super.illuminate()
      }
    }



    Вопрос 3Можно ли добавить stored property к типу, используя extension? Каким образом или почему нет?ответ

    Нет, это невозможно. Мы можем использовать extension, чтобы добавить новое поведение существующему типу, но не можем изменить сам тип или его интерфейс. Для хранения нового stored property нам потребуется дополнительная память, а extension не может это сделать.



    Вопрос 4Что такое протокол в Swift?ответ

    Протокол — это тип, который определяет набросок методов, свойств и т.д. Класс, структура или перечисление могут принимать протокол, чтобы реализовать все это. Протокол сам по себе не реализует функционал, но определяет его.




  • Advanced


    письменные вопросыВопрос 1Допустим, у нас есть структура, определяющая модель термометра:
    public struct Thermometer {
      public var temperature: Double
      public init(temperature: Double) {
        self.temperature = temperature
      }
    }

    Чтобы создать экземпляр, мы пишем:
    var t: Thermometer = Thermometer(temperature:56.8)

    Но было бы гораздо удобнее что-то вроде этого:
    var thermometer: Thermometer = 56.8

    Возможно ли это? Как?ответSwift определяет протоколы, которые позволяют инициализировать тип с использованием литералов путем присваивания. Применение соответствующего протокола и обеспечение публичного инициалайзера позволит инициализацию при помощи литералов. В случае Thermometer мы реализуем ExpressibleByFloatLiteral:
    extension Thermometer: ExpressibleByFloatLiteral {
      public init(floatLiteral value: FloatLiteralType) {
        self.init(temperature: value)
      }
    }

    Теперь мы можем создать экземпляр вот так:

    var thermometer: Thermometer = 56.8
    



    Вопрос 2У Swift есть набор предопределенных операторов для арифметических и логических действий. Он также позволяет создавать свои собственные операторы, как унарные, так и бинарные.

    Определите и реализуйте собственный оператор возведения в степень (^^) по следующим требованиям:

    • принимает в качестве параметров два Int
    • возвращает результат возведения первого параметра в степень второго
    • корректно обрабатывает порядок алгебраических операций
    • игнорирует возможные ошибки переполнения
    ответСоздание нового оператора происходит в два этапа: объявление и реализация.

    Объявление использует ключевое слово operator для задания типа (унарный или бинарный), для задания последовательности символов нового оператора, его ассоциативности и старшинства выполнения.

    Здесь оператор — это ^^ и его тип infix (бинарный). Ассоциативность правая.

    В Swift нет предопределенного старшинства для возведения в степень. В алгебре возведение в степень должно вычисляться перед умножением/делением. Таким образом, мы создаем пользовательский порядок выполнения, помещая возведение в степень выше умножения.

    Это объявление:

    precedencegroup ExponentPrecedence {
      higherThan: MultiplicationPrecedence
      associativity: right
    }
    infix operator ^^: ExponentPrecedence

    Это реализация:

    func ^^(base: Int, exponent: Int) -> Int {
      let l = Double(base)
      let r = Double(exponent)
      let p = pow(l, r)
      return Int(p)
    }



    Вопрос 3Следующий код определяет структуру Pizza и протокол Pizzeria с расширением для реализации по умолчанию метода makeMargherita():
    struct Pizza {
      let ingredients: [String]
    }
    
    protocol Pizzeria {
      func makePizza(_ ingredients: [String]) -> Pizza
      func makeMargherita() -> Pizza
    }
    
    extension Pizzeria {
      func makeMargherita() -> Pizza {
        return makePizza(["tomato", "mozzarella"])
      }
    }

    Теперь мы определяем ресторан Lombardis:

    struct Lombardis: Pizzeria {
      func makePizza(_ ingredients: [String]) -> Pizza {
        return Pizza(ingredients: ingredients)
      }
    
      func makeMargherita() -> Pizza {
        return makePizza(["tomato", "basil", "mozzarella"])
      }
    }
    

    Следующий код создает два экземпляра Lombardis. В котором из них делают маргариту с базиликом?
    let lombardis1: Pizzeria = Lombardis()
    let lombardis2: Lombardis = Lombardis()
    
    lombardis1.makeMargherita()
    lombardis2.makeMargherita()
    
    ответВ обоих. Протокол Pizzeria объявляет метод makeMargherita() и обеспечивает реализацию по умолчанию. Реализация Lombardis перекрывает метод по умолчанию. Так как мы объявили метод в протоколе в двух местах, будет вызвана правильная реализация.

    А что если бы протокол не объявлял метод makeMargherita(), а extension по-прежнему обеспечивал реализацию по умолчанию, вот так:

    protocol Pizzeria {
      func makePizza(_ ingredients: [String]) -> Pizza
    }
    
    extension Pizzeria {
      func makeMargherita() -> Pizza {
        return makePizza(["tomato", "mozzarella"])
      }
    }

    В этом случае только у lombardis2 была бы пицца с базиликом, тогда как у lombardis1 была бы без, потому что он использовал бы метод, определенный в extension.


    Вопрос 4Следующий код не компилируется. Можете объяснить, что с ним не так? Предложите варианты решения проблемы.
    struct Kitten {
    }
    
    func showKitten(kitten: Kitten?) {
      guard let k = kitten else {
        print("There is no kitten")
      }   
      print(k)
    }

    Подсказка: есть три способа исправить ошибку.
    ответБлок else оператора guard требует варианта выхода, или с использованием return, бросая исключение или вызывая @noreturn. Простейшее решение — добавить оператор return.
    func showKitten(kitten: Kitten?) {
      guard let k = kitten else {
        print("There is no kitten")
        return
      }
      print(k)
    }

    Это решение бросит исключение:
    enum KittenError: Error {
      case NoKitten
    }
    
    struct Kitten {
    }
    
    func showKitten(kitten: Kitten?) throws {
      guard let k = kitten else {
        print("There is no kitten")
        throw KittenError.NoKitten
      }
      print(k)
    }
    
    try showKitten(kitten: nil)

    Наконец, здесь вызов fatalError(), @noreturn-функция.

    struct Kitten {
    }
    
    func showKitten(kitten: Kitten?) {
      guard let k = kitten else {
        print("There is no kitten")
        fatalError()
      }
      print(k)
    }




    устные вопросыВопрос 1Замыкания — это ссылочный тип или тип-значение?ответ

    Замыкания — это ссылочный тип. Если вы присваиваете переменной замыкание, а затем копируете в другую переменную, вы копируете ссылку на то же самое замыкание и его список захвата.



    Вопрос 2Вы используете тип UInt для хранения беззнакового целого. Он реализует инициалайзер для конвертации из целого со знаком:
    init(_ value: Int)
    

    Однако, следующий код не скомпилируется, если вы зададите отрицательное значение:
    let myNegative = UInt(-1)

    Целые со знаком по определению не могут быть отрицательными. Однако, возможно использовать представление отрицательного числа в памяти для перевода его в беззнаковое.

    Как можно сконвертировать отрицательное целое в UInt с сохранением его представления в памяти?

    ответДля этого есть инициалайзер:
    UInt(bitPattern: Int)

    И использование:

    let myNegative = UInt(bitPattern: -1)



    Вопрос 3Опишите циклические ссылки в Swift? Как их можно исправить?ответЦиклические ссылки происходят, когда два экземпляра содержат сильную ссылку друг на друга, что приводит к утечке памяти из-за того, что ни один из этих экземпляров не может быть освобождён. Экземпляр не может быть освобождён, пока есть еще сильные ссылки на него, но один экземпляр держит другой.

    Это можно разрешить, заменив на одной из сторон ссылку, указав ключевое слово weak или unowned.



    Вопрос 4Swift разрешает создавать рекурсивные перечисления. Вот пример такого перечисления, которое содержит вариант Node с двумя ассоциативными типами, T and List:
    enum List<T> {
      case node(T, List<T>)
    }
    

    Здесь будет ошибка компиляции. Что мы пропустили?ответМы забыли ключевое слово indirect, которое позволяет подобные рекурсивные варианты перечисления:
    enum List<T> {
      indirect case node(T, List<T>)
    }




Почему Swift может стать большим событием в глубинном обучении / Хабр

Здравствуй, Хабр! Представляю вашему вниманию перевод заинтересовавшей меня статьи «Why Swift May Be the Next Big Thing in Deep Learning» автора Max Pechyonkin, в которой автор рассуждает о языке на котором будет осуществляться глубокое обучение в ближайшие годы.

Если вы занимаетесь глубинным обучением, то скорее всего вам стоит начать учить Swift

Вступление


Если вы занимаетесь программированием, то скорее всего когда вы слышите Swift, вы думаете о разработке приложений на IOS и MacOS. Если вы занимаетесь глубинным обучением, то вы должно быть слышали о Swift для Tensorflow(S4TF). Тогда вы можете задаться вопросом: «Почему Google создали версию TensorFlow для Swift? Ведь уже есть версии для Python и С++ то зачем еще один язык?» В этом посте, я попытаюсь ответить на этот вопрос и изложить причины почему стоит пристально следить за S4TF, а так же за самим языком Swift. Я не буду пытаться сделать подробный разбор, лишь попытаюсь описать общую картину с большим количеством ссылок, если вас заинтересует — вы можете копнуть глубже.

За Swift стоит очень сильная поддержка


Swift был создан Крисом Латтнером когда он работал в Apple. Сейчас же Крис работает в Google Brain (одной из самых лучших исследовательских команд в сфере искусственного интеллекта в мире). Уже сам факт того, что создатель языка Swift сейчас работает в лаборатории, которая занимается глубинным обучением, говорит о серьезности этого проекта.

Некоторое время назад люди в Гугл осознали, что даже если Пайтон и замечательный язык, в нем все равно есть очень много ограничений которые тяжело преодолеть. Понадобился новый язык для TensorFlow, и после долгого обдумывания Swift был выбран кандидатом. Я не буду вдаваться в детали здесь, но вот документ, который описывает недостатки Python, а так же какие другие языки были рассмотрены и как в итоге это все сошлось на Swift.

Swift для TensorFlow это намного больше чем просто библиотека


Swift для TensorFlow это не просто TF для еще одного языка. Это по сути другая ветвь(в git смысле) языка Swift как такового. Это означает что S4TF это не библиотека; это язык со своими собственными правилами, со своими встроенными функциями которые поддерживают всю функциональность требуемую TensorFlow. Например, в S4TF есть очень мощная система автоматического дифференцирования: она является одной из фундаментальных вещей в глубинном обучении, она нужна для расчетов градиентов. Сравните это с Python, в котором автоматическая дифференциация не является основным компонентом языка. Некоторые функции разработанные первоначально как часть S4TF были позже интегрированы в сам язык Swift.

Swift быстрый


Когда я впервые узнал что Swift настолько же быстрый, как и C, я был изумлен. Я знал что С был высоко оптимизированным и позволял достигнуть очень высокой скорости, но это происходило за счет микро управления памятью, и поэтому у С были проблемы с безопасностью памяти. Кроме того С не так просто и выучить.

Сейчас Swift работает так же быстро как и С в численных расчетах, у него нет проблем с безопасностью памяти, и его намного легче выучить. Компилятор LLVM у Swift очень мощный и у него очень эффективная оптимизация, она обеспечит очень быструю скорость работы кода.

Вы можете использовать Python, C и C++ в Swift


Поскольку Swift для машинного обучения находятся на очень ранней стадии своего развития, то для него не создано столько библиотек для МО. Вы не должны об этом сильно волноваться поскольку у Swift есть удивительная совместимость с Python с Python. Вы просто импортируете любую Python библиотеку в Swift, и она работает. Также вы можете импортировать С и С++ библиотеки в Swift(для С++ вы должны убедиться что заголовочные файлы написаны на чистом С, без функций С++).

Подводя итог, если вам нужна специфическая функциональность, но она еще не реализована в Swift, вы можете импортировать соответствующие Python, C или С++ пакеты.
Впечатляюще!

Swift может идти на очень низком уровне


Если вы когда-то пользовались TensorFlow, скорее всего вы делали это с помощью пакета для Python. Под капотом Python версия библиотеки TensorFlow использует С код на очень низком уровне. Поэтому когда вы вызываете функцию в TensorFlow, на каком-то уровне вы используете немного кода С. Это означает что есть предел того, насколько глубоко вы можете проверить исходный код. Например, если вы хотите посмотреть, как реализованы свертки(convolutions), вы не увидите код Python, потому что они реализованы на С.

В Swift же по другому. Крис Латтнер назвал Swift «синтаксическим сахаром для LLVM[язык ассемблера]». Это означает, что по сути, Swift работает практически напрямую с железом, и между нет никаких других строк кода написанных на С. Это так же означает что Swift очень быстрый, как я и описал выше. Это все приводит к тому, что вы, как разработчик можете проверить код как на очень высоком, так и на очень низком уровнях, без потребности использовать С.

Что дальше?


Swift это только одна часть тех инноваций в глубинном обучении которые готовят в Google. Есть еще один компонент, который так же очень сильно связан: MLIR, что означает многоуровневое промежуточное представление(Multi-level intermediate representation). MLIR будет объединяющей инфраструктурой компилятора, которая позволит писать код на Swift(или любом другом языке) и компилировать его на любом поддерживающем железе. Сейчас существует множество компиляторов для разного целевого оборудования, но MLIR сособен изменить это, позволит не только повторно использовать код, но и писать собственные низкоуровневые компоненты компилятора. Это так же позволит исследователям применять машинное обучение для оптимизации низкоуровневых алгоритмов.

Пока MLIR действует как компилятор для машинного обучения, мы так же видим возможность использования методов машинного обучения в компиляторах. Это особенно важно, так как количество инженеров разрабатывающих числовые библиотеки не растет так же быстро как растет разнообразие моделей или железа для машинного обучения.

Представьте возможность использовать глубинное обучение, чтобы оптимизировать низкоуровневые алгоритмы разбиения памяти на данные(похожую задачу пытается решить Halide). И это только начало, нас ждет еще много других креативных приложений использующих машинное обучение в компиляторах.

Итоги


Если вы в сфере глубинного обучения, тогда вам скорее всего стоит начать учить Swift. Это принесет много преимуществ по сравнению с Python. Google серьезно инвестирует в то чтобы Swift стал главным компонентом их TensorFlow ML инфраструктуры, и скорее всего Swift станет языком глубинного обучения. Если вы уже сейчас начнете учить и использовать Swift, то это даст вам преимущество первопроходца.

Как работает банк со своими корреспондентами по SWIFT

Итак, наш банк имеет открытые корреспондентские счета в США (CITIBANK N.A. NEW YORK), в Европе (VTB BANK DEUTSCHLAND AG), в России (Промсвязьбанк Москва и Собинбанк Москва).

Соответственно, все расследования по платежам происходят через эти банки согласно  установленным корреспондентским отношениям с использованием соответствующих форматов SWIFT MT-195/295, MT-196/296, MT-199/299 и MT-192/292

Кроме прямых корреспондентских отношений с банками, нашим банком установлены отношения и с другими финансовыми организациями через процедуру обмена ключами, что даёт возможность использовать SWIFT-форматы МТ-195, МТ-196 и МТ-199 для проведения процедуры расследования по стандартным платежам и платежам с покрытием:

- DEUTSCHE BANK TRUST COMPANY AMERICAS USA
- COMMERZBANK AG Germany
- CITIBANK N.A. London
- CITIBANK N.A. Brussels
- BANQUE DE COMMERCE ET DE PLACEMENTS S.A. Geneva
- NORVIK BANKA JSC  LV
- ABLV BANK AS  LV

В среднем процедура расследования занимает от 3 до 14 дней (если необходимо уточнить детали платежа: счёт получателя или наименование).

Многое зависит от колличества банков, которые задействованы в трафике платежа. Для
решения проблем используется переписка с банками-корреспондентами, контакт с кураторами счёта в соответствующих банках.Можно использовать Free Format MT-995/999, направляя их напрямую в банк-отправителя (при входящих платежах).

При необходимости можно контактировать с клиентами банка, а по возможности вступить в переписку с отправителями средств.

Что касается наиболее сложных ситуаций, то они связаны с процессом возврата ошибочно отправленных средств, а также со средствами, которые были отправлены банком, но не получены бенефициаром.

В некоторых случаях, это занимало достаточно времени, так как приходилось использовать все доступные инструменты:
- вести длительные переписки и общение как с банками, так и с клиентами, таким образом достигая позитивный результат.

По срокам, наиболее быстро решаются проблемы с банками Еврозоны и США.

Более сложно решать вопросы с Азиатскими банками (например, китайские банки не всегда идут на контакт) или Россией (связано с особенностями документооборота и не
всегда использованием SWIFT для быстрой передачи информации).

Базовые операторы - SwiftBook

Оператор — это специальный символ или выражение для проверки, изменения или сложения величин. Например, оператор сложения (+) суммирует два числа let i = 1 + 2, а логический оператор И && объединяет два логических значения if enteredDoorCode && passedRetinaScan.

Язык Swift поддерживает большинство стандартных операторов C, а также ряд возможностей для устранения типичных ошибок в коде. Оператор присваивания (=) не возвращает значение, что позволяет избежать путаницы с оператором проверки на равенство (==). Арифметические операторы (+, -, *, /, % и т. д.) могут обнаруживать и предотвращать переполнение типа, чтобы числовой переменной нельзя было присвоить слишком большое или слишком маленькое значение. Контроль переполнения типа включается в Swift специальными операторами, которые описаны в разделе Операторы переполнения.

В отличие от C язык Swift позволяет делить с остатком (%) числа с плавающей точкой. Также в Swift имеются два сокращенных оператора интервала (a..<b и a...b), которых нет в C.

В этой главе описываются стандартные операторы Swift. Более сложные операторы Swift рассмотрены в главе Продвинутые операторы, где описано, как объявить пользовательские операторы и реализовать стандартные операторы для пользовательских типов.

Операторы делятся на унарные, бинарные и тернарные:

  • Унарные операторы применяются к одной величине (например, -a). Унарные префиксные операторы ставятся непосредственно перед величиной (например, !b), а унарные постфиксные операторы — сразу за ней (например, c!).
  • Бинарные операторы применяются к двум величинам (например, 2 + 3) и являются инфиксными, так как ставятся между этими величинами.
  • Тернарные операторы применяются к трем величинам. Как и в языке C, в Swift есть только один такой оператор, а именно — тернарный условный оператор (a ? b : c).

Величины, к которым применяются операторы, называются операндами. В выражении 1 + 2 символ + является бинарным оператором, а его операндами служат 1 и 2.

Оператор присваивания (a = b) инициализирует или изменяет значение переменной a на значение b:

let b = 10
var a = 5
a = b
// теперь a равно 10

Если левая часть выражения является кортежем с несколькими значениями, его элементам можно присвоить сразу несколько констант или переменных:

let (x, y) = (1, 2)
// x равно 1, а y равно 2

В отличие от C и Objective-C оператор присваивания в Swift не может возвращать значение. К примеру, следующее выражение недопустимо:

if x = y {
 // это неверно, так как x = y не возвращает никакого значения
}

Эта особенность не позволяет разработчику спутать оператор присваивания (=) с оператором проверки на равенство (==). Благодаря тому, что выражения типа if x = y некорректны, подобные ошибки при программировании на Swift не произойдут.

Язык Swift поддерживает четыре стандартных арифметических оператора для всех числовых типов:

  • сложение (+)
  • вычитание (-)
  • умножение (*)
  • деление (/)
1 + 2 // равно 3
5 - 3 // равно 2
2 * 3 // равно 6
10.0 / 2.5 // равно 4.0

В отличие от C и Objective-C арифметические операторы Swift по умолчанию не допускают переполнения типа. Контроль переполнения типа включается в Swift специальными операторами (например, a &+ b). Подробнее см. в главе Операторы переполнения.

Оператор сложения служит также для конкатенации, или же склейки, строковых значений (тип String):

"hello, " + "world"  // равно "hello, world"

Оператор целочисленного деления

Оператор целочисленного деления (a % b) показывает, какое количество b помещается внутри a, и возвращает остаток деления a на b.

Заметка

Оператор целочисленного деления (%) в некоторых языках называется оператором деления по модулю. Однако учитывая его действие над отрицательными числами в Swift, этот оператор, строго говоря, выполняет деление с остатком, а не по модулю.

Оператор целочисленного деления работает следующим образом. Для вычисления выражения 9 % 4 сначала определяется, сколько четверок содержится в девятке:

В одной девятке содержатся две четверки, а остатком будет 1 (выделено оранжевым цветом).

На языке Swift это записывается так:

9 % 4    // равно 1

Чтобы получить результат деления a % b, оператор % вычисляет следующее выражение и возвращает остаток:

a = (b × множитель) + остаток

где множитель показывает, сколько раз целых b содержится в a.

Подставляя в это выражение 9 и 4, получим:

9 = (4 × 2) + 1

Точно так же рассчитывается остаток, когда a отрицательно:

-9 % 4   // равно -1

Подставляя в наше выражение -9 и 4, получим:

-9 = (4 × -2) + -1

причем остаток будет равен -1.

Если b отрицательно, его знак отбрасывается. Это означает, что выражения a % b и a % -b всегда будут давать одинаковый результат.

Оператор унарного минуса

Для изменения знака числового значения служит префиксный минус -, который называется оператором унарного минуса:

let three = 3
let minusThree = -three // minusThree равно -3
let plusThree = -minusThree // plusThree равно 3, т. е. "минус минус три"

Оператор унарного минуса (-) ставится непосредственно перед значением, без пробела.

Оператор унарного плюса

Оператор унарного плюса (+) просто возвращает исходное значение без каких-либо изменений:

let minusSix = -6
let alsoMinusSix = +minusSix // alsoMinusSix равно -6

Хотя оператор унарного плюса не выполняет никаких действий, он придает коду единообразие, позволяя зрительно отличать положительные значения от отрицательных.

Как и в языке C, в Swift имеются составные операторы присваивания, совмещающие простое присваивание (=) с другой операцией. Одним из примеров может служить оператор присваивания со сложением (+=):

var a = 1
a += 2
// теперь a равно 3

Выражение a += 2 является краткой формой записи a = a + 2. Таким образом, один и тот же оператор выполняет одновременно операцию сложения и присваивания.

Заметка

Составные операторы присваивания не возвращают значение. К примеру, нельзя написать так: let b = a += 2.

Для получения полного списка операторов присваивания, предусмотренных стандартной библиотекой Swift, см. Operator Declarations.

Язык Swift поддерживает все стандартные операторы сравнения из C:

  • равно (a == b)
  • не равно (a != b)
  • больше (a > b)
  • меньше (a < b)
  • больше или равно (a >= b)
  • меньше или равно (a <= b)
Заметка

В языке Swift есть также два оператора проверки на идентичность/тождественность (=== и !==), определяющие, ссылаются ли два указателя на один и тот же экземпляр объекта. Дополнительную информацию см. в главе Классы и структуры.

Каждый оператор сравнения возвращает значение типа Bool, указывающее, является ли выражение истинным:

1 == 1 // истина, так как 1 равно 1
2 != 1 // истина, так как 2 не равно 1
2 > 1 // истина, так как 2 больше чем 1
1 < 2 // истина, так как 1 меньше 2
1 >= 1 // истина, так как 1 больше либо равно 1
2 <= 1 // ложь, так как 2 не меньше либо равно 1

Операторы сравнения часто используются в условных выражениях, включая инструкцию if:

let name = "world"
if name == "world" {
 print("hello, world")
} else {
 print("Мне жаль, \(name), но я тебя не узнаю")
}
// напечатает "hello, world", так как name очевидно равно "world"

Подробнее об инструкции if см. в главе "Управление потоком".

Вы так же можете сравнивать кортежи, которые имеют одно и то же количество значений, которые, в свою очередь, должны быть сравниваемыми, что означает, что кортеж типа (Int, String) может быть сравнен с кортежем такого же типа.
Кортежи сравниваются слева направо, по одному значению за раз до тех пор, пока операция сравнения не найдет отличия между значениями. Если все значения кортежей попарно равны, то и кортежи так же считаются равными. Например:

(1, "zebra") < (2, "apple")   // true, потому что 1 меньше 2
(3, "apple") < (3, "bird")    // true , потому что 3 равно 3, а "apple" меньше чем "bird"
(4, "dog") == (4, "dog")      // true , потому что 4 равно 4 и "dog" равен "dog"

В примере выше, в первой строке вы можете видеть сравнение слева на право. Так как 1 меньше 2, то (1, “zebra”) меньше (2, “apple”), несмотря на остальные значения кортежа, потому что это неравенство было определено первыми членами. Не важно, что “zebra” не меньше, чем “apple”, потому что сравнение уже определено первыми элементами кортежей. Однако, когда первые элементы кортежей одинаковые, то сравниваются вторые элементы и так далее.

Кортежи могут сравниваться, только в том случае, если оператор сравнения можно применить ко всем членам кортежей соответственно. Например, как показано в коде ниже, вы можете сравнить два кортежа типа (String, Int) потому что и String, и Int могут сравниться оператором <. И наоборот, кортеж типа (String, Bool) сравниваться не может, так как к значениям типа Bool операторы сравнения не применяются.

("blue", -1) < ("purple", 1) // OK, расценивается как true
("blue", false) < ("purple", true) // Ошибка так как < не может применяться к значениям типа Bool 
Заметка

Стандартная библиотека Swift включает в себя операторы сравнения кортежей, которые имеют менее семи значений. Если вам нужны операторы, которые могут сравнивать кортежи с более, чем шестью элементами, то вам нужно реализовать их самостоятельно.

Тернарный условный оператор — это специальный оператор из трех частей, имеющий следующий синтаксис: выражение ? действие1 : действие2. Он выполняет одно из двух действий в зависимости от того, является ли выражение true или false. Если выражение равно true, оператор выполняет действие1 и возвращает его результат; в противном случае оператор выполняет действие2 и возвращает его результат.

Тернарный условный оператор является краткой записью следующего кода:

if выражение {
 действие1
} else {
 действие2
}

Ниже приведен пример расчета высоты строки в таблице. Если у строки есть заголовок, то она должна быть выше своего содержимого на 50 точек, а если заголовка нет, то на 20 точек:

let contentHeight = 40
let hasHeader = true
let rowHeight = contentHeight + (hasHeader ? 50 : 20)
// rowHeight равно 90

В развернутом виде этот код можно записать так:

let contentHeight = 40
let hasHeader = true
var rowHeight = contentHeight
if hasHeader {
    rowHeight = rowHeight + 50
} else {
    rowHeight = rowHeight + 20
}
// rowHeight равно 90

В первом примере с помощью тернарного условного оператора величине rowHeight в одну строку присваивается правильное значение. Этот вариант не только короче второго примера, но и позволяет объявить величину rowHeight константой, так как в отличие от конструкции if ее значение не нужно изменять.

Тернарный условный оператор — это короткая и удобная конструкция для выбора между двумя выражениями. Однако тернарный условный оператор следует применять с осторожностью. Избыток таких коротких конструкций иногда делает код трудным для понимания. В частности, лучше не использовать несколько тернарных условных операторов в одном составном операторе присваивания.

Оператор объединения по nil (a ?? b) извлекает опционал a, если он содержит значение, или возвращает значение по умолчанию b, если a равно nil. Выражение a может быть только опционалом. Выражение b должно быть такого же типа, что и значение внутри a.

Оператор объединения по nil является краткой записью следующего кода:

a != nil ? a! : b

В вышеприведенном коде тернарный условный оператор и принудительное извлечение (a!) используются для обращения к значению внутри a, если a не равно nil, или для возвращения b в противном случае. Оператор объединения по nil — это более элегантный, короткий и понятный способ одновременно проверить условие и извлечь значение.

Заметка

Если a не равно nil, выражение b не анализируется. Такой подход называется краткой проверкой условия (short-circuit evaluation).

В следующем примере оператор объединения по nil выбирает между стандартным значением цвета и пользовательским:

let defaultColorName = "red"
var userDefinedColorName: String? // по умолчанию равно nil
        
var colorNameToUse = userDefinedColorName ?? defaultColorName
// userDefinedColorName равен nil, поэтому colorNameToUse получит значение по умолчанию — "red"

Переменная userDefinedColorName объявлена как строковый (String) опционал и по умолчанию равна nil. Так как userDefinedColorName является опционалом, ее значение можно анализировать посредством оператора объединения по nil. В вышеприведенном примере этот оператор задает начальное значение для строковой (String) переменной colorNameToUse. Так как userDefinedColorName равно nil, выражение userDefinedColorName ?? defaultColorName возвратит значение defaultColorName, т. е. "red".

Если переменной userDefinedColorName присвоить отличное от nil значение и снова передать ее в оператор объединения по nil, вместо значения по умолчанию будет использовано значение внутри userDefinedColorName:

userDefinedColorName = "green"
colorNameToUse = userDefinedColorName ?? defaultColorName
// userDefinedColorName не равно nil, поэтому colorNameToUse получит значение "green"

В языке Swift есть два оператора диапазона, которые в короткой форме задают диапазон значений.

Оператор замкнутого диапазона

Оператор замкнутого диапазона (a...b) задает диапазон от a до b, включая сами a и b. При этом значение a не должно превышать b.

Оператор замкнутого диапазона удобно использовать при последовательном переборе значений из некоторого диапазона, как, например, в цикле for-in:

for index in 1...5 {
 print("\(index) умножить на 5 будет \(index * 5)")
}
// 1 умножить на 5 будет 5
// 2 умножить на 5 будет 10
// 3 умножить на 5 будет 15
// 4 умножить на 5 будет 20
// 5 умножить на 5 будет 25

Подробнее о циклах for-in см. в главе Управление потоком.

Оператор полузамкнутого диапазона

Оператор полузамкнутого диапазона (a..<b) задает диапазон от a до b, исключая значение b. Такой диапазон называется полузамкнутым, потому что он включает первое значение, но исключает последнее. Так же, как и для оператора замкнутого диапазона, значение a не должно превышать b. Если значение a равно значению b, то итоговый диапазон будет пустым.

Операторы полузамкнутого диапазона особенно удобны при работе с массивами и другими последовательностями, пронумерованными с нуля, когда нужно перебрать элементы от первого до последнего:

let names = ["Anna", "Alex", "Brian", "Jack"]
let count = names.count
for i in 0..<count {
 print("Person \(i + 1) будет \(names[i])")
}
// Person 1 будет Anna
// Person 2 будет Alex
// Person 3 будет Brian
// Person 4 будет Jack

Хотя в массиве четыре элемента, диапазон 0..<count доходит только до 3 (т. е. до номера последнего элемента в массиве), так как это оператор полузамкнутого диапазона. Подробнее о массивах см. в главе Массивы.

Односторонние диапазоны

Операторы замкнутого диапазона имеют себе альтернативу - диапазон, который продолжается насколько возможно, но только в одну сторону, например, диапазон, который включает все элементы массива, начиная от 2 и до последнего индекса. В этих случаях вы можете пропустить значение с одной стороны оператора диапазона. Этот тип диапазона называется односторонним, потому что оператор имеет значение только с одной стороны. Например:

for name in names[2...] {
    print(name)
}
// Brian
// Jack
 
for name in names[...2] {
    print(name)
}
// Anna
// Alex
// Brian

Оператор полузамкнутого диапазона так же имеет одностороннюю форму, которая записывается только с одним конечным значением. Точно так же как и в случае, когда вы включаете значение в обе стороны, конечное значение не является частью самого диапазона. Например:

for name in names[..<2] {
    print(name)
}
// Anna
// Alex

Односторонние диапазоны могут быть использованы в разных контекстах, а не только в сабскриптах. Вы не можете итерировать по одностороннему диапазону, который пропускает первое значение, потому что становится не очевидным, где должна начинаться итерация. Вы можете итерировать по одностороннему диапазону, который пропускает последнее значение, однако, так как диапазон длится бесконечно, убедитесь, что вы добавили условие окончание итерации в цикл. Вы так же можете проверить имеет ли односторонний диапазон конкретное значение, что показано ниже:

let range = ...5
range.contains(7)   // false
range.contains(4)   // true
range.contains(-1)  // true

Логические операторы изменяют или комбинируют логические значения типа Boolean (булево) — true и false. Язык Swift, как и другие C-подобные языки, поддерживает три стандартных логических оператора:

  • логическое НЕ (!a)
  • логическое И (a && b)
  • логическое ИЛИ (a || b)

Оператор логического НЕ

Оператор логического НЕ (!a) инвертирует булево значение — true меняется на false, а false становится true.

Оператор логического НЕ является префиксным и ставится непосредственно перед значением, без пробела. Как видно из следующего примера, его можно воспринимать как "не a":

let allowedEntry = false
if !allowedEntry {
 print("ACCESS DENIED")
}
// Выведет "ACCESS DENIED"

Конструкция if !allowedEntry означает "если не allowedEntry". Идущая за ней строка будет выполнена, только если "не allowedEntry" является истиной, т. е. если allowedEntry равно false.

Как видно из этого примера, удачный выбор булевой константы и имен переменных делает код коротким и понятным, без двойных отрицаний и громоздких логических выражений.

Оператор логического И

Оператор логического И (a && b) дает на выходе true тогда и только тогда, когда оба его операнда также равны true.

Если хотя бы один из них равен false, результатом всего выражения тоже будет false. На самом деле, если первое значение равно false, то второе даже не будет анализироваться, так как оно все равно не изменит общий результат на true. Такой подход называется краткой проверкой условия (short-circuit evaluation).

В следующем примере проверяются два значения типа Bool, и если они оба равны true, программа разрешает доступ:

let enteredDoorCode = true
let passedRetinaScan = false
if enteredDoorCode && passedRetinaScan {
 print("Welcome!")
} else {
 print("ACCESS DENIED")
}
// Выведет "ACCESS DENIED"

Оператор логического ИЛИ

Оператор логического ИЛИ (a || b) является инфиксным и записывается в виде двух вертикальных палочек без пробела. С его помощью можно создавать логические выражения, которые будут давать true, если хотя бы один из операндов равен true.

Как и описанный выше оператор логического И, оператор логического ИЛИ использует краткую проверку условия. Если левая часть выражения с логическим ИЛИ равна true, то правая не анализируется, так как ее значение не повлияет на общий результат.

В приведенном ниже примере первое значение типа Bool (hasDoorKey) равно false, а второе (knowsOverridePassword) равно true. Поскольку одно из значений равно true, результат всего выражения тоже становится true и доступ разрешается:

let hasDoorKey = false
let knowsOverridePassword = true
if hasDoorKey || knowsOverridePassword {
 print("Welcome!")
} else {
 print("ACCESS DENIED")
}
// Выведет "Welcome!"

Комбинирование логических операторов

Можно также составлять и более сложные выражения из нескольких логических операторов:

if enteredDoorCode && passedRetinaScan || hasDoorKey || knowsOverridePassword {
 print("Welcome!")
} else {
 print("ACCESS DENIED")
}
// Выведет "Welcome!"

В этом примере с помощью нескольких операторов && и || составляется более длинное и сложное выражение. Однако операторы && и || по-прежнему применяются только к двум величинам, поэтому все выражение можно разбить на три простых условия. Алгоритм работы будет следующим:

если пользователь правильно ввел код дверного замка и прошел сканирование сетчатки или если он использовал действующую ключ-карту или если он ввел код экстренного доступа, то дверь открывается.

Исходя из значений enteredDoorCode, passedRetinaScan и hasDoorKey первые два подусловия дают false. Однако был введен код экстренного доступа, поэтому все составное выражение по-прежнему равно true.

Заметка

Логические операторы Swift && и || являются лево-ассоциированными, что означает, что составные выражения с логическими операторами оценивают в первую очередь выражения слева направо.

Явное указание круглых скобок

Иногда имеет смысл использовать дополнительные круглые скобки, чтобы сложное логическое выражение стало проще для восприятия. В примере с открытием двери можно заключить в круглые скобки первую часть составного выражения, что сделает его нагляднее:

if (enteredDoorCode && passedRetinaScan) || hasDoorKey || knowsOverridePassword {
 print("Welcome!")
} else {
 print("ACCESS DENIED")
}
// Выведет "Welcome!"

Круглые скобки показывают, что первые две величины составляют одно из возможных значений всего логического выражения. Хотя результат составного выражения не изменится, такая запись сделает код понятнее. Читаемость кода всегда важнее краткости, поэтому желательно ставить круглые скобки везде, где они облегчают понимание.

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.

Swift - разработчик Apple

Современный

Swift - это результат последних исследований языков программирования в сочетании с многолетним опытом создания платформ Apple. Именованные параметры выражаются в чистом синтаксисе, что делает API в Swift еще проще для чтения и поддержки. Более того, вам даже не нужно вводить точку с запятой. Предполагаемые типы делают код более чистым и менее подверженным ошибкам, в то время как модули исключают заголовки и предоставляют пространства имен. Для наилучшей поддержки международных языков и эмодзи строки корректны для Юникода и используют кодировку на основе UTF-8 для оптимизации производительности для самых разных случаев использования.Память управляется автоматически с использованием точного детерминированного подсчета ссылок, что сводит использование памяти к минимуму без накладных расходов на сборку мусора.

  struct Player {
    имя переменной: Строка
    var highScore: Int = 0
    var history: [Int] = []

    init (_ имя: String) {
        self.name = имя
    }
}

var player = Player ("Томас")  

Объявите новые типы с помощью современного простого синтаксиса. Задайте значения по умолчанию для свойств экземпляра и определите настраиваемые инициализаторы.

  extension Player {
    мутирующая функция updateScore (_ newScore: Int) {
        history.append (newScore)
        если highScore  

Добавьте функциональность к существующим типам с помощью расширений и сократите количество шаблонов с помощью настраиваемых строковых интерполяций.

  extension Player: Codable, Equatable {}

импортный фундамент
пусть кодировщик = JSONEncoder ()
попробуйте кодировщик.закодировать (игрок)

печать (игрок)
  

Быстро расширяйте свои пользовательские типы, чтобы воспользоваться преимуществами мощных языковых функций, таких как автоматическое кодирование и декодирование JSON.

  let player = getPlayers ()


let ranked = Players.sorted (по: {player1, player2 в
    player1.highScore> player2.highScore
})


let rankedNames = ranked.map {$ 0.name}
  

Выполняйте мощные настраиваемые преобразования с помощью упрощенных замыканий.

Эти дальновидные концепции привели к созданию веселого и простого в использовании языка.

Swift имеет множество других функций, которые делают ваш код более выразительным:

  • Мощные и простые в использовании универсальные шаблоны
  • Расширения протокола, которые делают написание универсального кода еще проще
  • Функции первого класса и упрощенный синтаксис закрытия
  • Быстрая и лаконичная итерация по диапазону или коллекции
  • Кортежи и несколько возвращаемых значений
  • Структуры, поддерживающие методы, расширения и протоколы
  • Перечисления могут иметь полезные данные и поддерживать сопоставление с образцом
  • Шаблоны функционального программирования, e.г., карта и фильтр
  • Собственная обработка ошибок с помощью try / catch / throw

Создан для обеспечения безопасности

Swift устраняет целые классы небезопасного кода. Переменные всегда инициализируются перед использованием, массивы и целые числа проверяются на переполнение, память управляется автоматически, а принудительный монопольный доступ к памяти защищает от многих ошибок программирования. Синтаксис настроен так, чтобы упростить определение вашего намерения - например, простые трехсимвольные ключевые слова определяют переменную (var) или константу (let).И Swift сильно использует типы значений, особенно для часто используемых типов, таких как массивы и словари. Это означает, что когда вы делаете копию чего-либо с этим типом, вы знаете, что это не будет изменено где-либо еще.

Еще одна функция безопасности заключается в том, что по умолчанию объекты Swift никогда не могут быть нулевыми. Фактически, компилятор Swift не даст вам попытаться создать или использовать объект nil с ошибкой времени компиляции. Это делает написание кода намного чище и безопаснее, а также предотвращает огромную категорию сбоев времени выполнения в ваших приложениях.Однако бывают случаи, когда значение nil является допустимым и подходящим. Для таких ситуаций Swift имеет инновационную функцию, известную как optionals. Необязательный параметр может содержать nil, но синтаксис Swift заставляет вас безопасно работать с ним, используя? синтаксис, чтобы указать компилятору, что вы понимаете поведение и будете обрабатывать его безопасно.

  Коллекция расширений, где Element == Player {
    
    func highScoringPlayer () -> Player? {
        return self.max (by: {$ 0.highScore <$ 1.highScore})
    }
}  

Используйте опции, когда у вас может быть экземпляр для возврата из функции, а может и нет.

  if let bestPlayer = Players.highestScoringPlayer () {
    recordHolder = "" "
        Рекордсмен - \ (bestPlayer.name), \
        с высоким баллом \ (bestPlayer.highScore)!
        «»»
} else {
    recordHolder = "В игры еще не играли.")
}
печать (recordHolder)


let highScore = player.highestScoringPlayer () ?. highScore ?? 0
  

Такие функции, как дополнительное связывание, необязательное связывание и объединение с нулевым значением, позволяют безопасно и эффективно работать с необязательными значениями.

Быстрый и мощный

С самого начала своего появления Swift создавался, чтобы быть быстрым. Используя невероятно высокопроизводительную технологию компилятора LLVM, код Swift преобразуется в оптимизированный собственный код, позволяющий максимально эффективно использовать современное оборудование. Синтаксис и стандартная библиотека также были настроены так, чтобы наиболее очевидный способ написания кода также работал наилучшим образом, независимо от того, работает ли он в часах на вашем запястье или на кластере серверов.

Swift является преемником языков C и Objective-C.Он включает примитивы низкого уровня, такие как типы, управление потоком и операторы. Он также предоставляет объектно-ориентированные функции, такие как классы, протоколы и обобщения, предоставляя разработчикам Cocoa и Cocoa Touch требуемую производительность и мощность.

Отличный первый язык

Swift может открыть двери в мир программирования. Фактически, он был разработан, чтобы стать первым языком программирования, независимо от того, учитесь ли вы в школе или исследуете новые карьерные пути. Для преподавателей Apple создала бесплатную программу обучения Swift как в классе, так и вне его.Начинающие программисты могут загрузить Swift Playgrounds - приложение для iPad, которое делает начало работы с кодом Swift интерактивным и увлекательным.

Начинающие разработчики приложений могут получить доступ к бесплатным курсам, чтобы научиться создавать свои первые приложения в Xcode. А магазины Apple Store по всему миру проводят сеансы Today at Apple Coding & Apps, где вы можете получить практический опыт работы с кодом Swift.

Узнайте больше об образовательных ресурсах Swift от Apple

Исходная и двоичная совместимость

В Swift 5 вам не нужно изменять какой-либо код Swift 4 для использования новой версии компилятора.Вместо этого вы можете начать использовать новый компилятор и выполнять миграцию в своем собственном темпе, используя преимущества новых функций Swift 5, по одному модулю за раз. А Swift 5 теперь представляет двоичную совместимость для приложений. Это означает, что вам больше не нужно включать библиотеки Swift в приложения, предназначенные для текущих и будущих выпусков ОС, потому что библиотеки Swift будут включены в каждый выпуск ОС в будущем. Ваши приложения будут использовать последнюю версию библиотеки в ОС, и ваш код будет продолжать работать без перекомпиляции.Это не только упрощает разработку приложения, но и уменьшает размер приложения и время его запуска.

Открытый исходный код

Swift разрабатывается открыто на Swift.org, с исходным кодом, системой отслеживания ошибок, форумами и регулярными сборками для разработки, доступными для всех. Это широкое сообщество разработчиков, как внутри Apple, так и сотни сторонних разработчиков, работают вместе, чтобы сделать Swift еще более удивительным. Существует еще более широкий спектр блогов, подкастов, конференций и встреч, где разработчики из сообщества делятся своим опытом о том, как реализовать огромный потенциал Swift.

Кросс-платформенный

Swift уже поддерживает все платформы Apple и Linux, и члены сообщества активно работают над переносом на еще большее количество платформ. Сообщество SourceKit-LSP также работает над интеграцией поддержки Swift в широкий спектр инструментов разработчика. Мы рады видеть больше способов, с помощью которых Swift делает программное обеспечение более безопасным и быстрым, а также делает программирование более увлекательным.

Swift для сервера

Хотя Swift поддерживает многие новые приложения на платформах Apple, он также используется для нового класса современных серверных приложений.Swift идеально подходит для использования в серверных приложениях, которым требуется безопасность во время выполнения, производительность компиляции и небольшой объем памяти. Чтобы направить Swift в сторону разработки и развертывания серверных приложений, сообщество сформировало рабочую группу Swift Server. Первым продуктом этой работы стал SwiftNIO, кроссплатформенная платформа асинхронных событийно-управляемых сетевых приложений для высокопроизводительных протокольных серверов и клиентов. Он служит основой для создания дополнительных ориентированных на сервер инструментов и технологий, включая ведение журналов, метрики и драйверы баз данных, которые все находятся в активной разработке.

Чтобы узнать больше о сообществе Swift с открытым исходным кодом и рабочей группе Swift Server, посетите Swift.org

Детские площадки и цикл чтения-оценки-печати (REPL)

Как и Swift Playgrounds для iPad, игровые площадки в Xcode делают написание кода Swift невероятно простым и увлекательным. Введите строку кода, и результат появится немедленно. Затем вы можете быстро просмотреть результат со стороны вашего кода или закрепить результат прямо ниже. В представлении результатов могут отображаться графики, списки результатов или графики изменения значения во времени.Вы можете открыть помощник по временной шкале, чтобы наблюдать за развитием и анимацией сложного представления, что отлично подходит для экспериментов с новым кодом пользовательского интерфейса или для воспроизведения анимированной сцены SpriteKit по мере ее написания. Когда вы усовершенствовали свой код на игровой площадке, просто переместите этот код в свой проект. Swift также является интерактивным, когда вы используете его в терминале или в консоли отладки LLDB Xcode. Используйте синтаксис Swift для оценки и взаимодействия с вашим запущенным приложением или напишите новый код, чтобы увидеть, как он работает в среде, подобной сценарию.

Менеджер пакетов

Swift Package Manager - это единый кроссплатформенный инструмент для создания, запуска, тестирования и упаковки ваших библиотек и исполняемых файлов Swift.Пакеты Swift - лучший способ распространять библиотеки и исходный код среди сообщества Swift. Конфигурация пакетов написана на самом Swift, что упрощает настройку целей, объявление продуктов и управление зависимостями пакетов. Впервые в Swift 5 команда быстрого запуска теперь включает возможность импорта библиотек в REPL без необходимости создания исполняемого файла. Сам Swift Package Manager построен на Swift и включен в проект с открытым исходным кодом Swift как пакет.

Взаимодействие с Objective-C

Вы можете создать совершенно новое приложение с помощью Swift сегодня или начать использовать код Swift для реализации новых функций и возможностей в своем приложении.Код Swift сосуществует вместе с вашими существующими файлами Objective-C в одном проекте с полным доступом к API Objective-C, что упрощает внедрение.

,

Что такое SWIFT и как он работает?

Содержание

Наем независимых подрядчиков на Deel

Наем штатных сотрудников на Deel

Как производятся выплаты на Deel?

Deel бесплатно для подрядчиков

Цены Deel для компаний

Посмотреть Deel в действии

Вы платите за Deel сейчас, да?
Попробовать Deel

Вернуться в блог

Нашли эту статью полезной? Поделиться!

Если вас не интересуют подробности, но вы хотите узнать основы, прокрутите до конца и найдите краткую версию.:)

Что такое SWIFT?

SWIFT (Общество всемирных межбанковских финансовых телекоммуникаций) - это система обмена сообщениями, которая работает в сети финансовых учреждений по всему миру . Он используется тысячами банков по всему миру для безопасного и стандартизованного обмена информацией о финансовых транзакциях.

Поскольку SWIFT на самом деле не отправляет деньги, он требует различных вмешательств, что замедляет весь процесс.Это также увеличивает расходы на переводы.

Как работает SWIFT?

Давайте рассмотрим пример, который поможет вам лучше понять ситуацию.

Боб хочет отправить 100 долларов со своего банковского счета в США на банковский счет Патрика в Австралии.

Есть два сценария, основанные на отношениях между двумя банками.

Банки имеют устоявшиеся отношения

Если банки имеют устоявшиеся отношения, это означает, что у них есть коммерческие счета друг с другом.В этом случае все происходит проще и быстрее и выглядит примерно так:

  • Банк Боба отправит сообщение SWIFT в банк Патрика, которое часто приходит в считанные минуты.
  • Банк Боба списывает с его личного счета 100 долларов (деньги выходят. )
  • Банк Боба кредитует коммерческий банковский счет, открытый в банке Патрика (деньги поступают)
  • Банк Патрика кредитует его личный счет (деньги поступают)

В этом случае банки имеют устоявшиеся отношения, так что это достаточно легко перевести средства.

Банки не имеют установленной взаимосвязи

В этом случае все немного усложняется. Поскольку два банка не имеют коммерческих счетов друг с другом, банк-посредник используется для облегчения перевода. Банк-посредник - это место, где два других банка имеют коммерческие счета.

Как и в первом случае, банк Боба отправит сообщение SWIFT в банк Патрика, и они найдут нужный банк-посредник.Позвоним в банк-посредник Bank M.

Как только это будет сделано, процесс будет выглядеть следующим образом:

  • Банк Боба спишет с лицевого счета Боба 100 долларов (выходят деньги)
  • Банк Боба попросит банк M списать их коммерческий счет на 100 долларов и кредит на коммерческий счет банка Патрика
  • Банк M вычитает небольшую комиссию за посредничество (скажем, 1 доллар) из переводимой суммы и кредитует коммерческий счет банка Патрика на 99 долларов
  • Банк Патрика будет затем пополните личный счет Патрика на 99 долларов (деньги поступают)

Некоторые вещи происходят за кулисами, и поэтому этот процесс занимает время (обычно 3-5 рабочих дней), и взимается комиссия.

Иногда у двух банков нет коммерческих счетов в банке-посреднике, а это означает, что необходимо задействовать более одного банка-посредника. Как вы понимаете, это увеличивает время обработки и, конечно же, больше сборов.

Что происходит, когда задействованы разные валюты?

В этом сценарии к процессу добавляется еще один шаг - обмен валюты. Один из банков произведет обмен, и, скорее всего, по менее желательному курсу.Поэтому иногда стоимость трансфера достигает 65 долларов.

SWIFT - короткий и простой

SWIFT используется для передачи денежных переводов между двумя банками. Когда у двух банков есть отношения (коммерческие счета друг с другом), перевод осуществляется сразу после получения сообщения SWIFT. Деньги с личного счета переводятся на счет другого лица через коммерческие счета банка. Банки берут комиссию.

Если между двумя банками нет отношений, для облегчения процесса будет использоваться банк-посредник.За это взимается дополнительная плата.

Если в переводе участвуют две валюты, обмен валют будет произведен одним из банков.

.

SWIFT Значение? Все, что вам нужно знать о банковских переводах SWIFT

Переключить навигацию TransferWise зарегистрироваться
  • Блог
  • Новости
    • Сравнение
    • Корпоративный
    • Обновление продукта
    • Обновление команды
  • Личные финансы
    • Банковские счета
    • Коды банков
    • Денежный перевод
    • подсказок
  • Проживающих за рубежом
    • Недвижимость за рубежом
    • Обучение за рубежом
    • подсказок
    • Жизнь в
      Австралия
      Австрия
      Бельгия
      Бразилия
      Брюссель
      Канада
      Китай
      Хорватия
      Кипр
      Республика Чехия
      Дания
      Финляндия
      Франция
      Германия
      Греция
      Гонконг
      Индия
      Индонезия
      Ирландия
      Италия
      Япония
      Люксембург
      Малайзия
      Мальта
      Мексика
      Нидерланды
      Новая Зеландия
      Нигерия
      Норвегия
      Пакистан
      Перу
      Филиппины
      Польша
      Португалия
      Россия
      Сингапур
      Южная Африка
      Южная Корея
      Испания
      Швеция
      Швейцария
      Сидней
      Таиланд
      Вьетнам
      ОАЭ
      Великобритания
      Соединенные штаты
  • Путешествовать
    • Путешествие в
      Австралия
      Австрия
      Бангладеш
      Бельгия
      Бразилия
      Болгария
      Канада
      Чили
      Китай
      Колумбия
      Хорватия
.

SWIFT Значение? Все, что вам нужно знать о банковских переводах SWIFT

Переключить навигацию TransferWise зарегистрироваться
  • Блог
  • Новости
    • Сравнение
    • Корпоративный
    • Обновление продукта
    • Обновление команды
  • Личные финансы
    • Банковские счета
    • Коды банков
    • Денежный перевод
    • подсказок
  • Проживающих за рубежом
    • Недвижимость за рубежом
    • Обучение за рубежом
    • подсказок
    • Жизнь в
      Австралия
      Австрия
      Бельгия
      Бразилия
      Канада
      Китай
      Хорватия
      Кипр
      Республика Чехия
      Дания
      Финляндия
      Франция
      Германия
      Греция
      Гонконг
      Индия
      Индонезия
      Ирландия
      Италия
      Япония
      Люксембург
      Малайзия
      Мальта
      Мексика
      Нидерланды
      Новая Зеландия
      Нигерия
      Норвегия
      Пакистан
      Перу
      Филиппины
      Польша
      Португалия
      Россия
      Сингапур
      Южная Африка
      Южная Корея
      Испания
      Швеция
      Швейцария
      Таиланд
      Вьетнам
      ОАЭ
      Великобритания
      Соединенные штаты
  • Путешествовать
    • Праздничные деньги
    • подсказок
    • Планирование поездки
    • Путешествие в
      Австралия
      Австрия
      Бангладеш
      Бельгия
      Бразилия
      Болгария
      Канада
      Чили
      Китай
.



Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *