Использование Swift if let с логическим оператором AND &&

93

Мы знаем, что можем использовать if letоператор в качестве сокращения, чтобы проверить наличие необязательного nil, а затем развернуть.

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

Так, например, здесь я выполняю необязательную цепочку, чтобы развернуть и, при необходимости, уменьшить свой rootViewController до tabBarController. Но вместо того, чтобы иметь вложенные операторы if, я бы хотел их объединить.

if let tabBarController = window!.rootViewController as? UITabBarController {
    if tabBarController.viewControllers.count > 0 {
        println("do stuff")
     }
 }

Комбинированная подача:

if let tabBarController = window!.rootViewController as? UITabBarController &&
    tabBarController.viewControllers.count > 0 {
        println("do stuff")
     }
}

Вышеуказанное дает ошибку компиляции. Использование неразрешенного идентификатора tabBarController.

Упрощение:

if let tabBarController = window!.rootViewController as? UITabBarController && true {
   println("do stuff")
}

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

Итак, вопрос в том, возможно ли это, и если да, то каков правильный синтаксис?

Обратите внимание , что я хочу сделать это с ifзаявлением не в switchзаявлении или тройным ?оператором.

Макс Маклауд
источник
Всегда рекомендуется указывать сообщения об ошибках в вопросе.
zaph 08
Более простое утверждение для людей, которые любят экспериментировать с этим:var foo : Int? = 10; if let bar = foo { if bar == 10 { println("Great success!") }}
DarkDust
Сообщение об ошибке при использовании if let bar = foo && bar == 10есть Use of unresolved identifier "bar"(на втором bar, конечно).
DarkDust
просто примечание, что я смог сократить приведенный выше пример с помощью firstObject цели C следующим образом: if let navigationController = tabBarController.viewControllers.bridgeToObjectiveC (). firstObject as? UINavigationController {
Макс МакЛауд
1
1. bridgeToObjectiveCотсутствует в бета-версии 5 (и, вполне возможно, никогда не предназначался для общего использования). 2. В любом случае есть firstметод встроенного Arrayтипа Swift .
rickster

Ответы:

143

В Swift 1.2 это возможно . В примечаниях к выпуску бета-версий Swift 1.2 и Xcode 6.3 говорится :

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

С приведенным выше утверждением синтаксис будет таким:

if let tabBarController = window!.rootViewController as? UITabBarController where tabBarController.viewControllers.count > 0 {
        println("do stuff")
}

Здесь используется whereпредложение.

Другой пример, на этот раз приведение AnyObjectк Int, разворачивание необязательного и проверка того, что развернутый необязательный элемент соответствует условию:

if let w = width as? Int where w < 500
{
    println("success!")
}

Для тех, кто сейчас использует Swift 3, «где» заменено запятой. Таким образом, эквивалент будет:

if let w = width as? Int, w < 500
{
    println("success!")
}
Макс Маклауд
источник
2
Это должен быть выбранный ответ.
Francis Beauchamp
да, как сейчас изменилось. Ответ Брайана был правильным на тот момент
Макс МакЛауд
59

В Swift 3 Max пример Маклеода выглядел бы так:

if let tabBarController = window!.rootViewController as? UITabBarController, tabBarController.viewControllers.count > 0 {
    println("do stuff")
}

whereБыл заменен,

ph1lb4
источник
10
Итак, это для &&, что есть для || ?
jeet.chanchawat
9
@ jeet.chanchawat логическое ИЛИ не имеет смысла в этом контексте. if letможет продолжаться только в том случае, если необязательный параметр успешно развернут и ему присвоено новое имя переменной. Если бы вы сказали, OR <something else>вы могли бы легко обойти всю цель if let. Для логического ИЛИ просто выполните обычное ifи внутри тела дело с тем фактом, что первый объект все еще является необязательным в этой точке (не развернутым).
jhabbott
37

Ответ Макса правильный и один из способов сделать это. Обратите внимание, что когда написано так:

if let a = someOptional where someBool { }

someOptionalВыражение будет решен первым. Если это не удается, someBoolвыражение не будет оцениваться (оценка короткого замыкания, как и следовало ожидать).

Если вы хотите написать это наоборот, это можно сделать так:

if someBool, let a = someOptional { }

В таком случае someBool сначала оценивается, и только если оно истинно, someOptionalвычисляется выражение.

номинал
источник
5

Swift 4 , я буду использовать,

let i = navigationController?.viewControllers.index(of: self)
if let index = i, index > 0, let parent = navigationController?.viewControllers[index-1] {
    // access parent
}
Сазад Хисейн Хан
источник
4

Это невозможно.

Из грамматики Swift

ГРАММАТИКА ЗАЯВЛЕНИЯ IF

оператор ifif if-condition code-block else-clauseopt

если-условие → выражение | декларация

else-clause → else кодовый блок | иначе if-заявление

Значение любого условия в операторе if должно иметь тип, соответствующий протоколу BooleanType. Условие также может быть необязательным объявлением привязки, как описано в разделе Необязательная привязка

Если-условие должно быть выражением или объявлением. У вас не может быть одновременно выражения и декларации.

let foo = barявляется декларацией, она не оценивает значение, которое соответствует BooleanType. Он объявляет константу / переменную foo.

Ваше исходное решение достаточно хорошее, оно гораздо более читабельно, чем сочетание условий.

Брайан Чен
источник
но, конечно же, «if let» - что является допустимым синтаксисом Swift - одновременно является выражением и объявлением?
Макс МакЛауд
@MaxMacLeod let foo = bar- это объявление, а не выражение. вы не можете сделатьlet boolValue = (let foo = bar)
Брайан Чен
хорошо, но если процитировать руководство по Swift, стр. 11, то пример: if let name = optionalName. optionalName должно быть выражением, посредством которого, если optionalName не является необязательным, оно оценивается как истинное. Затем начинается вторая часть оператора, в соответствии с которой развернутый необязательный параметр присваивается имени. Итак, вопрос в том, что если «optionalName не является необязательным» является выражением, можно ли его расширить с помощью логического И. Кстати, я думаю, вы, вероятно, правы в том, что это невозможно.
Макс МакЛауд,
-1

Я думаю, что ваше первоначальное предложение не так уж и плохо. Альтернативой (более сложной) будет:

if ((window!.rootViewController as? UITabBarController)?.viewControllers.count ?? 0) > 0 {
    println("do stuff")
}
jtbandes
источник
1
но вам нужно ввести код, чтобы tabBarControllerповторить трансляцию
Брайан Чен