根据SE-0054,ImplicitlyUnwrappedOptional<T> 不再是一个独特的类型;现在只有Optional<T>。
仍然允许将声明注释为隐式解包选项T!,但这样做只是添加一个隐藏属性以通知编译器它们的值可能在需要解包类型T的上下文中被强制解包;他们的实际类型现在是T?。
所以你可以想到这个声明:
var str: String!
实际上是这样的:
@_implicitlyUnwrapped // this attribute name is fictitious
var str: String?
只有编译器才能看到这个@_implicitlyUnwrapped 属性,但它允许在需要String(它的展开类型)的上下文中隐式展开str 的值:
// `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
let y: Any = str // `str` is implicitly coerced from `String?` to `Any`
print(str) // Same as the previous example, as `print` takes an `Any` parameter.
编译器总是更喜欢这样对待它而不是强制展开。
正如提案所说(强调我的):
如果表达式可以使用强可选类型进行显式类型检查,那么它将是。但是,如果需要,类型检查器将退回到强制可选。这种行为的影响是任何引用声明为T! 的值的表达式的结果都将具有T 类型或T? 类型。
当涉及到字符串插值时,编译器在后台使用_ExpressibleByStringInterpolation protocol 中的这个初始化程序来评估字符串插值段:
/// 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 是nil,两者都会崩溃。