使用隐式解包的选项但是测试nil vs可选绑定是否有技术上的缺点?

Mar*_*eIV 3 optional swift optional-binding

好的,所以我知道在Swift中使用选项的正常方法是通过可选的绑定来解开它们,就像这样......

let stringA:String? = nil // (or "ABC")

if let unwrappedStringA = stringA
{
    let x:String = unwrappedStringA
}
Run Code Online (Sandbox Code Playgroud)

但是我也看到了使用隐式解包的选项的以下方式,我个人认为它看起来更干净,因为它不仅不需要额外的变量,而且它"读取"更好,更像英语(即'如果这是不是,然后......')可读性是Swift的核心原则之一(特别是在即将推出的Swift 3.0中).

let stringA:String! = nil // (or "ABC")

if stringA != nil
{
    let x:String = stringA
}
Run Code Online (Sandbox Code Playgroud)

然而,就后者而言,斯威夫特的"纯粹主义者"将此称为"代码嗅觉"并坚持认为它是"坏,坏,坏!!"......但他们从未解释过为什么!那么......为什么这么糟糕?

注意:是的,我知道可选链接和其他这些功能,你不能使用隐式解包的选项,它们都是非常酷的功能,但我特别询问测试隐式解包的选项对nil的技术缺点vs可选绑定.

我希望的是可量化的技术原因,为什么一个比另一个好(即编译器优化,更好的安全检查,性能等)换句话说,不仅仅是'嘿,因为那不是'Swifty'的方式去做吧!' 希望有道理.

更新

我实际上刚刚找到了一种方法来解决我的一个问题(至少是表面的方式),它必须创建一个新变量来保存未包装的变量.这里的技巧是因为展开的变量实际上与可选的本身不同,你可以使用完全相同的名称.

此外,括号内部还有另一个范围,它也可以有一个名为stringA的变量.这意味着你现在可以拥有三个'stringA'变量(但并不意味着你应该!)......

  1. 可选的
  2. 打开的可选项
  3. 括号内的新的局部变量

这是这个疯狂的代码显示这个......

let stringA:String? = nil // (or "ABC") // First stringA variable

if let stringA = stringA
{
    let x:String = stringA // <- This stringA is the unwrapped optional (the second stringA)

    // Now we're just getting crazy (and smelly!)
    let stringA = stringA + stringA // <- This is yet another stringA (third one!)
    let y:String = stringA 
}
Run Code Online (Sandbox Code Playgroud)

再一次,我不是在纵容这个!! 我只是从一个有启发性的角度展示其他人可能会感兴趣的代码.我确定做到了!

and*_*n22 8

确实有一个简单的原因,这是你列出的一个:"更好的安全检查".可选绑定保持编译器已知的解包范围,而程序员有责任跟踪您何时检查或未检查隐式解包的可选项nil.

使用可选绑定:

let stringA:String? = nil // (or "ABC")

if let unwrappedStringA = stringA
{
    let x:String = unwrappedStringA
}

accidentallyAttemptingToUse(stringA) // Compiler error! I see my mistake.
Run Code Online (Sandbox Code Playgroud)

隐式展开:

let stringA:String! = nil // (or "ABC")

if(stringA != nil)
{
    let x:String = stringA
}

accidentallyAttemptingToUse(stringA) // Runtime crash I might find in testing. Yuck.
Run Code Online (Sandbox Code Playgroud)

什么 IUO有益?

为什么要隐含地打开选项呢?它们的存在基本上只有一个目的:肯定会有值的属性,但直到稍后init才有,所以它们必须是可选的.通常@IBOutlet属于这一类:你可以相信他们有一个价值,你不想一直打开它们,但是它们没有被分配init,所以你必须让它们成为可选的.就是隐含的解包方案.

展开到同名变量

您的更新暂时建议将选项包装到具有相同名称的变量中,实际上是优秀的 Swift风格,并且早期和经常被Apple使用.当您打开同名变量时,代码更容易阅读,因为您可以跟踪更少(和更好)的名称.绝对拥抱这个!

let stringA:String? = nil // (or "ABC")

if let stringA = stringA
{
    let x:String = stringA // Of *course* this is still named `stringA`;
    // it's representing the same concept, after all.
}
Run Code Online (Sandbox Code Playgroud)


vac*_*ama 5

由于Swift 3中隐式解包选项更改,如果您正确解包常规选项而不是使用隐式解包的选项,您会更高兴.

Swift 3中,如果String!为新变量赋值,则该变量将具有该类型String?.这意味着你的隐式展开成为可选分配上经常可选的,你现在要处理的展开新的变量.

此代码适用于Swift 2.x:

let stringA: String! = "Hello"

if stringA != nil
{
    let y = stringA
    let z = y + " world!"
}
Run Code Online (Sandbox Code Playgroud)

Swift 3中:

let stringA: String! = "Hello"

if stringA != nil
{
    let y = stringA
    let z = y + " world!"  // ERROR: value of optional type 'String?' not unwrapped; did you mean to use '!' or '?'?
}
Run Code Online (Sandbox Code Playgroud)

如果您使用String?并打开它,那么代码在Swift 2.xSwift 3中按预期工作:

let stringA: String? = "Hello"

if let stringA = stringA
{
    let y = stringA
    let z = y + " world!"
}
Run Code Online (Sandbox Code Playgroud)

请参阅此处有关此更改的官方讨论:SE-0054:废除隐式解包的可选类型

本文件的" 动机"部分指出[强调添加我的]:

ImplicitlyUnwrappedOptional("IUO")类型是用于导入Objective-C API的有用工具,其中未指定参数或返回类型的可为空性.它还代表了一种在初始化器中处理明确初始化问题的便捷机制. 但是,IUO是一种过渡技术; 它们代表了一种简单的 方法来解决未标注的API或缺乏语言功能 ,可以更优雅的处理代码的某些模式.因此,我们 希望限制其使用前进,并引入更 具体的语言功能来取代它们.除了一些 特定情况,选项总是更安全的赌注,我们希望 鼓励人们使用它们而不是IUO.

该提案旨在将IUO的采用限制在 实际需要 它们的地方,并且 其他技术不必要,将Swift语言放在完全从系统中删除隐式未包装选项的路径上.它还完全废除了IUO的任何概念,低于编译器的类型检查器级别,这将大大简化编译器实现.

这清楚地表明语言设计者认为你应该尽可能少使用Implicitly Unwrapped Optionals.