Используя "if let..." со многими выражениями

Эта идиома Свифта имеет смысл

if let x = someDict[someKey] { ... }

Однако я действительно хочу

if let x = someDict[someKey], y = someDict[someOtherKey] { ... }

Как написано, это неверно, но возможно ли это?

Ответ 1

Обновление для Swift 1.2

Так как Swift 1.2, if let позволяет разворачивать несколько опций, поэтому теперь вы можете просто написать это, как в вашем примере:

if let x = someDict[someKey], y = someDict[someOtherKey] { … }

Вы можете даже чередовать условия, такие как:

if let x = someDict[someKey] where x == "value", y = someDict[someOtherKey] { … }

Это было раньше, чем Swift 1.2

Вот как вы могли бы сделать это без уродливой силы-upwrapping:

switch (dict["a"], dict["b"]) {
case let (.Some(a), .Some(b)):
    println("match")
default:
    println("no match")
}

На самом деле все еще довольно многословно.

Это работает, потому что необязательный тип формы Type? фактически сокращен для Optional<Type>, который представляет собой перечисление, которое выглядит примерно так:

enum Optional<T> {
    case None
    case Some(T)
}

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

Изменить: Я видел, как люди пишут вспомогательные функции, подобные этой (извините за отсутствие атрибуции, я не помню, где я ее видел):

func unwrap<A, B>(a: A?, b: B?) -> (A, B)? {
    switch (a, b) {
    case let (.Some(a), .Some(b)):
        return (a, b)
    default:
        return nil
    }
}

Затем вы можете продолжать использовать конструкцию if let, а именно:

if let (a, b) = unwrap(dict["a"], dict["b"]) {
    println("match: \(a), \(b)")
} else {
    println("no match")
}

Ответ 2

В Swift 1.2 (часть Xcode 6.3), if let необязательная конструкция привязки может связывать несколько опций, используя тот же синтаксис, который найден в этом вопросе.

if let x = someDict[someKey], y = someDict[someOtherKey] { ... }

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

if let a = foo(), b = bar(), a < b, let c = baz() { ... }

Шаблон switch для обработки множественного необязательного связывания (см. этот ответ) остается в силе. Хотя с условиями if let guard вы можете найти меньше вариантов использования для него, оно все еще существует, если вы хотите, например, обрабатывать случаи множественного необязательного связывания с различным поведением, когда разные подмножества тестируемых опций являются нулевыми.

(Примечание: до Swift 3, if let a = ..., b = ..., a < b используется where, чтобы разделить привязку с условным.)

Ответ 3

В Swift1.2 вы можете использовать несколько необязательных привязок.

if let x = someDict[someKey], y = someDict[someOtherKey] { ... }

Обратите внимание, что y неявно объявляется как константа, что совпадает с x. Вышеприведенный код эквивалентен следующему.

if let x = someDict[someKey],let y = someDict[someOtherKey] { ... }

Если вы хотите явно объявить y как изменяемый тип, просто введите var перед именем переменной.

if let x = someDict[someKey],var y = someDict[someOtherKey] { ... }