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。 相反,它现在是一个常规的Optional
types – 它只是有一个属性,允许编译器强制拆包,在它不能作为一个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的Optional
types,因此这意味着它不会被强制解包。
相反,如果你拿一个带有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
,这两者都会崩溃。