Я пытаюсь присвоить значение 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?. Я думаю, что тот факт, что это необязательная строка, важен.
Один try может охватывать все выражение, например guard let x = try f("a") ?? f("b") ?? f("c") else {...}
@Hamish Ваше предложение исправляет мою ошибку а также, делает мой код более читабельным. Спасибо! Пожалуйста, не стесняйтесь опубликовать это как ответ.
@Hamish Разве это не остановится на первой ошибке? Я думаю, что это работает иначе, чем исходный код.
@Sulthan Ключевое слово try на самом деле не влияет на поведение программы, компилятор просто требует его, чтобы сделать выдачу ошибок явным. Независимо от того, где вы поместите ключевое слово, функция завершится при первой выданной ошибке.
@JoshParadroid Конечно!
Связано: Функция выдает И возвращает необязательно.. можно ли условно развернуть в одну строку?
@hamish, чтобы было понятно, у него не будет той же функциональности, что и у версии с try?, которая продолжит выполнение после ошибок.
@Sulthan Султан Ах да, верно. Извините, когда вы сказали «исходный код», я предположил, что вы имеете в виду первый блок кода в вопросе ОП. Насколько я понимаю, поведение try - это то, что хочет ОП.





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