Отказ от ответственности: Я не был уверен, должен ли я добавить это в качестве дополнения к своему вопросу или я должен опубликовать его в качестве ответа. Я решил для последнего. Это не пуленепробиваемое объяснение, но я думаю, что оно «достаточно близко» для многих, кто может столкнуться с той же проблемой.
Что не так: Общая картина
Двакомментарии о том, что предоставленный код не компилируется для комментаторов, подтолкнули меня в правильном направлении:
Я скопировал код на пустой площадке и запустил его. Для меня он сделал компиляцию, но он также показал предупреждение, которое не отображалось до (потому что по какой-то причине предупреждения об автозаполнении и компиляторе были нарушены в исходном проекте) .
Предупреждение
Выражение, неявно приведенное от «Any?»в 'Any'
говорит мне, что выражение (optionalError ?? defaultString)
, по-видимому, оценивается как тип Any?
, что является необязательным. Затем компилятор выбирает операторную функцию ??
(1) для оценки всего выражения, которое требует, чтобы его значение по умолчанию (optionalError ?? defaultString)
было необязательным. Таким образом, это значение неявно приводится от Any?
до Any
. И именно поэтому печатается Optional(MyError.anError)
.
Почему это идет не так?
Осталось два вопроса:
- Почему компилятор выбираетоператорная функция (1)?
- Почему
(optionalError ?? defaultString)
оценивается как Any?
?
У меня нет ответа на вопрос 1 ,
но я предполагаю, что компилятор просто назначает более высокий приоритет функции (1), когда типы параметров не совпадают, и неясно, какую функцию использовать. (Я буду рад, если меня поправят.)
Относительно вопрос 2 :
optionalError
относится к типу MyError?
, а defaultString
относится к типу String
. Подпись операторских функций ??
гласит:
func ?? <T>(optional: T?, defaultValue: @autoclosure () throws -> T) rethrows -> T
func ?? <T>(optional: T?, defaultValue: @autoclosure () throws -> T?) rethrows -> T?
Итак, оба параметра, optional
и defaultValue
должен иметь «тот же» универсальный тип (только то, что в первом случае один параметр является необязательным для этого конкретного типа, а другой - нет). MyError
и String
, очевидно, не одного типа. Таким образом, чтобы это соответствовало критериям сигнатуры функции, компилятор должен привести оба типа к Any
.
Так что MyError?
приведен к Any?
и, по-видимому, String
также приведенAny?
и, таким образом, используется функция (2), которая оценивает (optionError ?? defaultString) to
Any? `.
Это снова поднимает вопрос, почему в этом случае используется функция (2), котораяВ некотором роде это противоречит моему предположению о вопросе (1), но Мой основной вывод здесь заключается в том, что использование двух разных типов с оператором nil-coalescing .
* - это просто плохая идея. 1094 * Справочная информация:
Я получил этот пример кода из учебника по RxSwift, который немного отличается, поскольку в нем используется универсальный тип, который требуется для соответствия CustomStringConvertible
:
func print<T: CustomStringConvertible>(label: String, event: Event<T>) {
print(label, event.element ?? event.error ?? event)
}
Во-первых, что заставило меня поэкспериментировать с этим, так это то, что когда я запускал код из книги, он печатал необязательный, в то время как книга утверждала, что печатает необязательный.