/ Swift

Swift Syntax Cheat Codes (Перевод)

Является ли это вашим первым языком или вы начинаете с Objective-C, язык Swift буквально является бомбой с точки зрения написания кода. И это может быть немного пугающим, если вы не знакомы с улучшением синтаксиса, который он имеет. В этом посте будет рассмотрен и детализирован некоторый общий синтаксис, с которым вы столкнетесь при чтении и научитесь писать сжатый код с помощью Swift.

Closures (Замыкание)

() -> Void

Иначе эти функции называются "неназванными функциями" или "блоки" в С и Objective-C. Замыкание — это в значительной степени миниатюрная функция, которая может быть передана как значение, обычно в аргументах функции, но так же как и переменная.

Если у вас есть предыдущий опыт разработки приложений на IOS, вы, скорей всего, взаимодействовали с ними при использовании API анимации UIView:

class func animate(withDuration duration: NSTimeInterval, animations: @escaping () -> Void)

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

UIView.animate(withDuration: 10.0, animations: {
    button.alpha = 0
})

Функция animationWithDuration: будет использовать наше замыкание и сделает некоторую потрясающию закулисную магию, чтобы заставить нашу кнопку медленно исчезать 0%.

Trailing closures (Последующее замыкание)

UIView.animate(withDuration: 10.0) {
    button.alpha = 0
}

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

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

func say(_ message: String, completion: @escaping () -> Void) {
    print(message)
    completion()
}
say("Hello", completion: {
    // prints: "Hello"
    // Do some other stuff
})
say("Hello") {
    // prints: "Hello"
    // Do some other stuff
}

Type Alias (Псевдонимы типов)

typealias

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

func dance(do: (Int, String, Double) -> (Int, String, Double)) { }

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

func dance(do: (Int, String, Double) -> (Int, String, Double)) { }
func sing(do: (Int, String, Double) -> (Int, String, Double)) { }
func act(do: (Int, String, Double) -> (Int, String, Double)) { }

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

typealias TripleThreat = (Int, String, Double) -> (Int, String, Double)
...
func dance(dance: TripleThreat) { }
func act(act: TripleThreat) { }
func sing(sing: TripleThreat) { }

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

Famous Type Aliases (Известные псевдонимы типов)

typealias Void = ()
typealias NSTimeInterval = Double

Shorthand argument names (Сокращенные имена аргументов)

$0, $1, $2...

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

func say(_ message: String, completion: (_ goodbye: String) -> Void) {
    print(message)
    completion("Goodbye")
}
...
say("Hi") { (goodbye: String) -> Void in
    print(goodbye)
}
// prints: "Hi"
// prints: "Goodbye"

В этом примере для нашего последующего замыкания определен один аргумент с именем goodbye:, который имеет тип String, Xcode автоматически поместит его внутри кортежа, за которым следует in, чтобы обозначить тип возврата в конце аргументов, а затем мы выполним наш код на следующей строке. Однако, когда мы знаем, что наши замыкания невелики по объему, эту подробность можно считать лишней. Давайте начнем разбирать и уменьшаем этот код до абсолютного минимума.

(goodbye: String) -> Void in

Фактически код не нужен, потому что мы можем просто использовать сокращенные имена аргументов.

say("Hi") { print($0) }
// prints: "Hi"
// prints: "Goodbye"

Как вы можете видеть, мы пропустили название goodbye: имя аргумента, декларацию типа Void и суффикс in, который следует за ним, потому что мы не используем имена аргументов. Каждый аргумент назван по порядку, который был объявлен в замыкании, и, поскольку он настолько прост, мы можем просто поместить его всего в одну строку.

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

(goodbye: String, name: String, age: Int) -> Void in
// $0: goodbye
// $1: name
// $2: age

Closures Are Reference Types (Замыкания - ссылочный тип)

-> Self

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

[1, 2, 3, nil, 5]
    .flatMap { $0 }     // remove nils
    .filter { $0 < 3 }  // filter numbers that are greater than 2
    .map { $0 * 100 }   // multiply each value by 100
// [100, 200]

Это круто?! Это настолько элегантно, легко читается и понятно, что мы должны вставлять его во многих местах!

Допустим, мы создаем extension для String, где мы выполняем кучу операций над самой строкой, вместо того, чтобы возвращать функции Void, мы возвращаем Self:

// extension UIView
func with(backgroundColor: UIColor) -> Self {
    backgroundColor = color
    return self
}
func with(cornerRadius: CGFloat) -> Self {
    layer.cornerRadius = 3
    return self
}
...
let view = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 10))
          .with(backgroundColor: .black)
          .with(cornerRadius: 3)

Резюме

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

Ссылка на оригинальную статью