根据
SE-0054,
ImplicitlyUnwrappedOptional<T>
不再是一个独立的类型;现在只有
Optional<T>
。
声明仍然允许被标注为隐式解包可选项
T!
,但这样做只是添加了一个隐藏属性来告诉编译器它们的值可能会在需要其解包类型
T
的上下文中被强制解包;它们的实际类型现在是
T?
。
所以你可以将这个声明看作:
var str: String!
实际上看起来是这样的:
@_implicitlyUnwrapped // this attribute name is fictitious
var str: String?
只有编译器能看到这个@_implicitlyUnwrapped
属性,但它允许在需要String
(它的解包类型)的上下文中隐式地解包str
的值:
let x: String = str
print(str.count)
但在所有其他情况下,如果str
可以被类型检查为强制可选项,那么它将是一个强制可选项:
let x = str
let y: Any = str
print(str)
编译器总是更倾向于将其视为强制解包,而不是强制展开。
正如提案所说(重点在于我):
如果表达式可以使用强可选类型进行显式类型检查,那么就会这样做。但是,如果必要的话,类型检查器将退回到强制使用可选项。这种行为的效果是,任何引用声明为 T!
的值的表达式的结果都将具有类型 T
或类型 T?
。
当涉及到字符串插值时,在幕后编译器使用_ExpressibleByStringInterpolation
协议中的此初始化程序来评估字符串插值段:
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,只需使用强制解包运算符
!
即可:
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
,这两者都会崩溃。
str
为nil
时会发生什么:print("The following should not be printed as an optional: \(str ?? "")")
。 - hasheminil
检查。而且 - 如其名所示 - 编译器应该为您完成所有的解包操作,但它没有这么做。 - Keiwan