Как я могу использовать try с оператором объединения?

Я пытаюсь присвоить значение x из функции f, которая принимает один параметр (строку) и выдает результат.

Текущий прицел бросает, поэтому я считаю, что do...catch не требуется.

Я пытаюсь использовать try с оператором объединения ??, но получаю эту ошибку: 'try' cannot appear to the right of a non-assignment operator.

guard let x = try f("a") ??
              try f("b") ??
              try f("c") else {
    print("Couldn't get a valid value for x")
    return
}

Если я заменю try на try?:

guard let x = try? f("a") ??
              try? f("b") ??
              try? f("c") else {
    print("Couldn't get a valid value for x")
    return
}

Я получаю предупреждение Left side of nil coalescing operator '??' has non-optional type 'String??', so the right side is never used и ошибку: 'try?' cannot appear to the right of a non-assignment operator.

Если я поставлю каждую попытку? в скобках:

guard let x = (try? f("a")) ??
              (try? f("b")) ??
              (try? f("c")) else {
    print("Couldn't get a valid value for x")
    return
}

Он компилируется, но x является необязательным, и я хотел бы, чтобы он был развернут.

если убрать знаки вопроса:

guard let x = (try f("a")) ??
              (try f("b")) ??
              (try f("c")) else {
    print("Couldn't get a valid value for x")
    return
}

Я получаю ошибку Operator can throw but expression is not marked with 'try'.

Я использую Swift 4.2 (последний в Xcode на момент написания).

Как правильно это сделать, чтобы получить развернутое значение в x?

Обновлять:*f() возвращает тип String?. Я думаю, что тот факт, что это необязательная строка, важен.

Я думаю, что вы должны начать с удаления дубликатов и сделать что-то вроде let x = ['a', 'b', 'c'].lazy.compactMap { try? f($0) }.first.

Sulthan 06.03.2019 12:05

Один try может охватывать все выражение, например guard let x = try f("a") ?? f("b") ?? f("c") else {...}

Hamish 06.03.2019 12:24

@Hamish Ваше предложение исправляет мою ошибку а также, делает мой код более читабельным. Спасибо! Пожалуйста, не стесняйтесь опубликовать это как ответ.

Josh Paradroid 06.03.2019 12:37

@Hamish Разве это не остановится на первой ошибке? Я думаю, что это работает иначе, чем исходный код.

Sulthan 06.03.2019 12:47

@Sulthan Ключевое слово try на самом деле не влияет на поведение программы, компилятор просто требует его, чтобы сделать выдачу ошибок явным. Независимо от того, где вы поместите ключевое слово, функция завершится при первой выданной ошибке.

Hamish 06.03.2019 12:53

@JoshParadroid Конечно!

Hamish 06.03.2019 12:53

@hamish, чтобы было понятно, у него не будет той же функциональности, что и у версии с try?, которая продолжит выполнение после ошибок.

Sulthan 06.03.2019 13:24

@Sulthan Султан Ах да, верно. Извините, когда вы сказали «исходный код», я предположил, что вы имеете в виду первый блок кода в вопросе ОП. Насколько я понимаю, поведение try - это то, что хочет ОП.

Hamish 07.03.2019 00:01
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
8
9
1 036
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Один try может покрыть все выражение, поэтому вы можете просто сказать:

  guard let x = try f("a") ?? f("b") ?? f("c") else {
    print("Couldn't get a valid value for x")
    return
  }

То же самое касается try?:

  guard let x = try? f("a") ?? f("b") ?? f("c") else {
    print("Couldn't get a valid value for x")
    return
  }

Хотя обратите внимание, что в Swift 4.2 x будет String? из-за того, что вы применяете try? к уже необязательному значению, давая вам двойную оболочку, которая guard let будет разворачивать только один слой.

Чтобы исправить это, вы можете объединиться с nil:

  guard let x = (try? f("a") ?? f("b") ?? f("c")) ?? nil else {
    print("Couldn't get a valid value for x")
    return
  }

Но в Swift 5 в этом нет необходимости из-за SE-0230, где try? f("a") ?? f("b") ?? f("c") будет автоматически сведено компилятором в одно необязательное значение.

Альтернативой для Swift < 5 может быть (двойной) необязательный шаблон: guard case let x?? = try? f("a") ?? f("b") ?? f("c")

Martin R 06.03.2019 13:00

Другие вопросы по теме