#swift
#swift
Вопрос:
Я пытаюсь присвоить значение 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?. Я думаю, важен тот факт, что это необязательная строка.
Комментарии:
1. Я думаю, что вам следует начать с удаления дубликатов и сделать что-то вроде
let x = ['a', 'b', 'c'].lazy.compactMap { try? f($0) }.first
.2. Одно
try
может охватывать все выражение, напримерguard let x = try f("a") ?? f("b") ?? f("c") else {...}
3. @Hamish Ваше предложение исправляет мою ошибку и делает мой код более читаемым. Спасибо! Пожалуйста, не стесняйтесь публиковать это в качестве ответа.
4. @JoshParadroid Конечно!
5. @Sulthan Ах да, да, это правильно. Извините, когда вы сказали «исходный код», я предположил, что вы имели в виду первый блок кода в вопросе OP. Насколько я понимаю,
try
поведение — это то, чего хочет OP.
Ответ №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")
компилятор автоматически сведет в одно необязательное значение.
Комментарии:
1. Альтернативой для Swift < 5 был бы (двойной) необязательный шаблон:
guard case let x?? = try? f("a") ?? f("b") ?? f("c")