Свифт 3 неправильная строка интерполяции с неявно развернутые опции
почему неявно развернутые опции не разворачиваются при использовании Строковой интерполяции в Swift 3?
пример: Запуск следующего кода на игровой площадке
var str: String!
str = "Hello"
print("The following should not be printed as an optional: (str)")
производит этот выход:
The following should not be printed as an optional: Optional("Hello")
конечно, я могу объединить строки с +
оператор, но я использую строку интерполяции почти везде в моем приложении, которое теперь не работает больше из-за этого (ошибка?).
это даже ошибка или они намеренно изменили это поведение с помощью Swift 3?
1 ответ:
по состоянию на SE-0054,
ImplicitlyUnwrappedOptional<T>
больше не является отдельным типом; есть толькоOptional<T>
сейчас.объявления по-прежнему могут быть аннотированы как неявно развернутые опционные
T!
, но это просто добавляет скрытый атрибут, чтобы сообщить компилятору, что их значение может быть принудительно развернуто в контекстах, которые требуют их развернутого типаT
; их фактический тип сейчасT?
.так что вы можете думать об этом объявление:
var str: String!
как на самом деле выглядит примерно так:
@_implicitlyUnwrapped // this attribute name is fictitious var str: String?
только компилятор видит это
@_implicitlyUnwrapped
атрибут, но то, что он позволяет это неявное разворачиваниеstr
значение в контекстах, которые требуютString
(его развернул тип):// `str` cannot be type-checked as a strong optional, so the compiler will implicitly // force unwrap it (causing a crash in this case) let x: String = str // We're accessing a member on the unwrapped type of `str`, so it'll also be implicitly // force unwrapped here print(str.count)
но во всех остальных случаях, когда
str
можно тип-проверить как сильное опционное, оно будет:// x is inferred to be a String? (because we really are assigning a String?) let x = str // str is implicitly coerced from String? to Any let y: Any = str
и компилятор всегда будет предпочитать рассматривать его как таковой над силой развертка.
как говорится в предложении (Курсив мой):
если выражение может быть явно тип проверен с сильным необязательным типом, это будет. Однако при необходимости средство проверки типов вернется к принудительному принудительному использованию. Эффект такого поведения заключается в том, что результат любого выражения, которое ссылается на значение, объявленное как
T!
либо будет иметь типT
или типаT?
.когда дело доходит до Строковой интерполяции, под капотом компилятор использует этот инициализатор из
_ExpressibleByStringInterpolation
протокол чтобы оценить сегмент интерполяции строки:/// Creates an instance containing the appropriate representation for the /// given value. /// /// Do not call this initializer directly. It is used by the compiler for /// each string interpolation segment when you use string interpolation. For /// example: /// /// let s = "\(5) x \(2) = \(5 * 2)" /// print(s) /// // Prints "5 x 2 = 10" /// /// This initializer is called five times when processing the string literal /// in the example above; once each for the following: the integer `5`, the /// string `" x "`, the integer `2`, the string `" = "`, and the result of /// the expression `5 * 2`. /// /// - Parameter expr: The expression to represent. init<T>(stringInterpolationSegment expr: T)
поэтому при неявном вызове вашим кодом:
var str: String! str = "Hello" print("The following should not be printed as an optional: \(str)")
как
str
фактический тип -String?
, по умолчанию это то, что компилятор будет выводить общий заполнительT
быть. Поэтому значениеstr
не будет принудительно развернут, и вы в конечном итоге увидите описание для дополнительного.если вы хотите, чтобы IUO был принудительно развернут при использовании в интерполяции строк, вы можете просто использовать оператор force unwrap
!
:var str: String! str = "Hello" print("The following should not be printed as an optional: \(str!)")
или вы можете принудить к его необязательному типу (в этом случае
String
) для того, чтобы заставить компилятор неявно развернуть его для вас:print("The following should not be printed as an optional: \(str as String)")
оба из которых, конечно, рухнет, если
str
isnil
.