Swift 3不正确的string插值隐式解包选项

为什么在Swift 3中使用string插值时隐式解包的选项不会被解开?

示例 :在操场中运行以下代码

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") 

当然,我可以使用+运算符连接string,但是在我的应用程序中,我几乎在任何地方都使用string插值,现在由于这个(bug?)而不再工作了。

这甚至是一个错误,或者他们故意用Swift 3改变这种行为?

按照SE-0054 , ImplicitlyUnwrappedOptional不再是一个独特的types。 相反,它现在是一个常规的Optionaltypes – 它只是有一个属性,允许编译器强制拆包,在它不能作为一个types检查的情况下。

正如提案所言(重点是我的):

如果expression式可以使用强可选types进行显式types检查,则会是 。 但是,如果需要的话,types检查器将回退到强制选项。 这种行为的影响是任何expression式的结果引用一个声明为T!的值T! 会有T型还是T?T?

这意味着,当进行types推断时,编译器总是倾向于将隐式解包的可选项作为一个可Optional来input,而不是强制解包它。 但是,当提供显式types注释时,这种行为将被覆盖。

当涉及到string插值时,编译器使用_ExpressibleByStringInterpolation协议中的这个初始化函数来评估string插值段:

 /// 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) 

由于这个初始化器使用一个通用的参数(没有显式的types注解),所以编译器能够推断出参数T是一个隐式解开的可选input的Optionaltypes,因此这意味着它不会被强制解包。

相反,如果你拿一个带有Any参数的print() (一个明确的抽象types注解),编译器将不能推断IUOinput是Optional ,因此它被隐式地强制解开。

如果你希望一个IUO在使用string插值的时候强制展开,你可以简单地使用force unwrap操作符!

 var str: String! str = "Hello" print("The following should not be printed as an optional: \(str!)") 

或者你可以强制转换为它的非可选types(在这种情况下是String ),以强制编译器隐式地强制为你打开它:

 print("The following should not be printed as an optional: \(str as String)") 

当然,如果str nil ,这两者都会崩溃。