Swift 3不正确的字符串插值,带有隐式展开的Optionals [英] Swift 3 incorrect string interpolation with implicitly unwrapped Optionals

查看:114
本文介绍了Swift 3不正确的字符串插值,带有隐式展开的Optionals的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Swift 3中使用字符串插值时,为什么没有隐式解包的可选内容未解包?

Why are implicitly unwrapped optionals not unwrapped when using string interpolation in Swift 3?

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

Example: Running the following code in the playground

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

当然,我可以使用+运算符连接字符串,但是我在应用程序的几乎所有地方都使用了字符串插值,由于这个原因,现在不再起作用了(错误?).

Of course I can concatenate strings with the + operator but I'm using string interpolation pretty much everywhere in my app which now doesn't work anymore due to this (bug?).

这甚至是一个错误,还是他们有意使用Swift 3更改了此行为?

Is this even a bug or did they intentionally change this behaviour with Swift 3?

推荐答案

根据

As per SE-0054, ImplicitlyUnwrappedOptional<T> is no longer a distinct type; there is only Optional<T> now.

仍然允许将声明注释为隐式未包装的可选内容T!,但是这样做只是添加了一个隐藏属性,以告知编译器在需要其未包装类型T的上下文中,它们的值可能会被强制包装.现在其实际类型为T?.

Declarations are still allowed to be annotated as implicitly unwrapped optionals T!, but doing so just adds a hidden attribute to inform the compiler that their value may be force unwrapped in contexts that demand their unwrapped type T; their actual type is now T?.

因此您可以想到以下声明:

So you can think of this declaration:

var str: String!

实际上看起来像这样:

@_implicitlyUnwrapped // this attribute name is fictitious 
var str: String?

只有编译器看到此@_implicitlyUnwrapped属性,但它允许的是在需要String(其未包装类型)的上下文中对str值的隐式展开:

Only the compiler sees this @_implicitlyUnwrapped attribute, but what it allows for is the implicit unwrapping of str's value in contexts that demand a String (its unwrapped type):

// `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类型检查为强壮可选项的情况下,它将是:

But in all other cases where str can be type-checked as a strong optional, it will be:

// `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.

与编译器相比,编译器将始终更喜欢将其视作强制展开.

And the compiler will always prefer treating it as such over force unwrapping.

如提案所说(强调我的意思):

As the proposal says (emphasis mine):

如果可以使用强可选类型显式地检查表达式,则它将为.但是,如果需要,类型检查器将转为强制使用可选.此行为的结果是,任何引用声明为T!的值的表达式的结果都将具有T类型或T? 类型.

If the expression can be explicitly type checked with a strong optional type, it will be. However, the type checker will fall back to forcing the optional if necessary. The effect of this behavior is that the result of any expression that refers to a value declared as T! will either have type T or type T?.

关于字符串插值,在后台,编译器使用

When it comes to string interpolation, under the hood the compiler uses this initialiser from the _ExpressibleByStringInterpolation protocol in order to evaluate a string interpolation segment:

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

因此,当您的代码隐式调用时:

Therefore when implicitly called by your code:

var str: String!
str = "Hello"

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

由于str的实际类型为String?,因此默认情况下,编译器将推断出通用占位符T为.因此,str的值不会被强制解包,您最终将看到可选内容的说明.

As str's actual type is String?, by default that's what the compiler will infer the generic placeholder T to be. Therefore the value of str won't be force unwrapped, and you'll end up seeing the description for an optional.

如果希望在字符串插值中使用时将IUO强制展开,则只需使用强制展开操作符!:

If you wish for an IUO to be force unwrapped when used in string interpolation, you can simply use the force unwrap operator !:

var str: String!
str = "Hello"

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

或您可以强制使用其非可选类型(在本例中为String),以强制编译器隐式强制为您解包:

or you can coerce to its non-optional type (in this case String) in order to force the compiler to implicitly force unwrap it for you:

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

如果strnil,则两者都会崩溃.

both of which, of course, will crash if str is nil.

这篇关于Swift 3不正确的字符串插值,带有隐式展开的Optionals的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆