Swift, почему распаковка необязательна, защита от NIL не работает - PullRequest
1 голос
/ 15 января 2020

Я новичок в Swift, но мне любопытно поведение необязательного развертывания.

Есть ли какое-либо объяснение, почему защита от != nil не разворачивает необязательное развертывание?

Как просто пример:

func hasC(_ s: String?) -> Bool {
  guard s != nil else {
    return false
  }

  return s!.contains("c")
}

Мне нужно поставить восклицательный знак и явно развернуть значение, даже если кажется, что в последней строке s больше не является необязательной строкой.

Мне бы хотелось услышать причину такого поведения и как правильно развернуть значение в таком случае?

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

guard let s = s else { ... }

и защита от не логическое условие не работает:

guard s else { ... }

Repl: https://repl.it/@valerii / необязательно-развернуть

Ответы [ 5 ]

3 голосов
/ 15 января 2020

Тип s по-прежнему Optional, поэтому неважно, сделали вы проверку nil или нет. Проверка nil выполняется во время выполнения, в то время как система типов выполняет проверку во время компиляции. Единственный способ гарантировать, что s никогда не может быть nil, - через необязательную привязку if let или guard let.

2 голосов
/ 15 января 2020

Простой ответ заключается в том, что оператор приравнивания, например ==, != или любые операторы сравнения, не имеет ничего общего с развертыванием необязательного значения с точки зрения компилятора.
A guard оператор имеет 2 общих варианта использования. Одним из них является защита от значения boolean, которое создается оператором сравнения или сравнения, как в следующем примере:

guard ["foo", "bar"].contains("foo") == true else { return }
guard 10 > 5 else { return }

В то время как другая роль оператора guard заключается в развертывании необязательных параметров, который записан в синтаксисе guard let или guard var. Например:

guard let unwrappedValue = anOptionalValue else { return }

Этот указанный синтаксис c позволяет компилятору узнать, что вы пытаетесь развернуть значение, и в результате вы получите развернутое значение, если развертывание выполнено успешно.

Конечно, при создании другой переменной / константы может показаться "уродливым", это путь к go в Swift.

0 голосов
/ 15 января 2020

вы используете неправильный формат

func hasC(_ s: String?) -> Bool {
  guard let input = s else {return false}

  return input.contains("c")
}

, и вы можете сделать так:

func hasC(_ s: String?) -> Bool {
  if let input = s {
  return input.contains("c")
  }
  return false
}

или вы можете сделать свой вывод обнуляемым следующим образом:

func hasC(_ s: String?) -> Bool? {
      return s?.contains("c")
}

или

func hasC(_ s: String?) -> Bool {
        return s?.contains("c") ?? false
}

это уже не безобразно. с нижними строчками. С наилучшими пожеланиями

0 голосов
/ 15 января 2020

guard ничего не разворачивает само по себе. Это как особый вид if. guard let разворачивается, но это просто синтакти c сахар.

0 голосов
/ 15 января 2020

Вы не объявляете новую переменную с помощью guard, параметр функции является необязательным, поэтому его можно развернуть даже после оператора guard

func hasC(_ s: String?) -> Bool {
    if let containsValueInString  = s ,   containsValueInString.contains("c"){
         return true
    }
    return false

}

или проще, вы можете использовать опциональное сцепление с оператором объединения nil

func hasC(_ s: String?) -> Bool {
  return  s?.contains("c") ?? false

}
...