Использование нескольких let-in внутри оператора if в Swift

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

var latitude : AnyObject! = imageDictionary["latitude"]
var longitude : AnyObject! = imageDictionary["longitude"]

if let latitudeDouble = latitude as? Double  {
   if let longitudeDouble = longitude as? Double {
       // do stuff here
   }
}

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

if let latitudeDouble = latitude as? Double, longitudeDouble = longitude as? Double {
    // do stuff here
}

Этот синтаксис не работает, поэтому мне было интересно, есть ли прекрасный способ сделать это.

Ответ 1

Обновление для Swift 3:

В Swift 3 будет работать следующее:

if let latitudeDouble = latitude as? Double, let longitudeDouble = longitude as? Double {
    // latitudeDouble and longitudeDouble are non-optional in here
}

Просто не забудьте вспомнить, что если одна из попыток необязательных привязок терпит неудачу, код внутри блока if-let не будет выполнен.

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

Например:

if let latitudeDouble = latitude as? Double, importantThing == true {
    // latitudeDouble is non-optional in here and importantThing is true
}

Swift 1.2:

Apple, возможно, прочитала ваш вопрос, потому что ваш код надежного компиляции правильно в Swift 1.2 (в бета-версии сегодня):

if let latitudeDouble = latitude as? Double, longitudeDouble = longitude as? Double {
    // do stuff here
}

Swift 1.1 и ранее:

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

var latitude: Any! = imageDictionary["latitude"]
var longitude: Any! = imageDictionary["longitude"]

switch (latitude, longitude) {
case let (lat as Double, long as Double):
    println("lat: \(lat), long: \(long)")
default:
    println("Couldn't understand latitude or longitude as Double")
}

Обновление: Эта версия кода теперь работает правильно.

Ответ 2

Swift 3.0

if let latitudeDouble = latitude as? Double, let longitudeDouble = longitude as? Double {
    // do stuff here
}

Ответ 3

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


1. Использование if let (необязательная привязка/необязательная цепочка)

Swift Язык программирования указывает на необязательную цепочку:

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

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

let dict = ["latitude": 2.0 as AnyObject?, "longitude": 10.0 as AnyObject?]
let latitude = dict["latitude"]
let longitude = dict["longitude"]

if let latitude = latitude as? Double, let longitude = longitude as? Double {
    print(latitude, longitude)
}

// prints: 2.0 10.0

2. Использование кортежей и привязка значений в операторе switch

В качестве альтернативы простой необязательной цепочке оператор switch может предлагать мелкозернистую решение при использовании с кортежами и привязкой значений:

let dict = ["latitude": 2.0 as AnyObject?, "longitude": 10.0 as AnyObject?]
let latitude = dict["latitude"]
let longitude = dict["longitude"]

switch (latitude, longitude) {
case let (Optional.some(latitude as Double), Optional.some(longitude as Double)):
    print(latitude, longitude)
default:
    break
}

// prints: 2.0 10.0
let dict = ["latitude": 2.0 as AnyObject?, "longitude": 10.0 as AnyObject?]
let latitude = dict["latitude"]
let longitude = dict["longitude"]

switch (latitude, longitude) {
case let (latitude as Double, longitude as Double):
    print(latitude, longitude)
default:
    break
}

// prints: 2.0 10.0
let dict = ["latitude": 2.0 as AnyObject?, "longitude": 10.0 as AnyObject?]
let latitude = dict["latitude"]
let longitude = dict["longitude"]

switch (latitude as? Double, longitude as? Double) {
case let (.some(latitude), .some(longitude)):
    print(latitude, longitude)
default:
    break
}

// prints: 2.0 10.0
let dict = ["latitude": 2.0 as AnyObject?, "longitude": 10.0 as AnyObject?]
let latitude = dict["latitude"]
let longitude = dict["longitude"]

switch (latitude as? Double, longitude as? Double) {
case let (latitude?, longitude?):
    print(latitude, longitude)
default:
    break
}

// prints: 2.0 10.0

3. Использование кортежей с if case (дополнительный шаблон)

if case (необязательный шаблон) предоставляет удобный способ развернуть значения необязательного перечисления. Вы можете использовать его с кортежами, чтобы выполнить некоторую дополнительную цепочку с несколькими запросами:

let dict = ["latitude": 2.0 as AnyObject?, "longitude": 10.0 as AnyObject?]
let latitude = dict["latitude"]
let longitude = dict["longitude"]

if case let (.some(latitude as Double), .some(longitude as Double)) = (latitude, longitude) {
    print(latitude, longitude)
}

// prints: 2.0 10.0
let dict = ["latitude": 2.0 as AnyObject?, "longitude": 10.0 as AnyObject?]
let latitude = dict["latitude"]
let longitude = dict["longitude"]

if case let (latitude as Double, longitude as Double) = (latitude, longitude) {
    print(latitude, longitude)
}

// prints: 2.0 10.0
let dict = ["latitude": 2.0 as AnyObject?, "longitude": 10.0 as AnyObject?]
let latitude = dict["latitude"]
let longitude = dict["longitude"]

if case let (.some(latitude), .some(longitude)) = (latitude as? Double, longitude as? Double) {
    print(latitude, longitude)
}

// prints: 2.0 10.0
let dict = ["latitude": 2.0 as AnyObject?, "longitude": 10.0 as AnyObject?]
let latitude = dict["latitude"]
let longitude = dict["longitude"]

if case let (latitude?, longitude?) = (latitude as? Double, longitude as? Double) {
    print(latitude, longitude)
}

// prints: 2.0 10.0