【问题标题】:Returning an implicitly unwrapped optional返回一个隐式展开的可选
【发布时间】:2015-01-16 20:32:39
【问题描述】:

我正在用 Swift 编写一个程序,它具有各种应该总是返回值的函数,但在某些情况下不能,因此程序崩溃并提醒用户错误。为了实现这一点,我使用隐式展开的 Optionals 作为函数的返回值,这样错误情况就可以返回 nil(即使永远不会到达该代码)。它看起来像这样:

func giveMeAThing() -> Thing! {
    if !possibleErrorCase() {
        var thing = createAThingForSure()
        return thing
    }
    else {
        crashAndBurn()
        return nil
    }
}

写这个,感觉有点hacky,所以我的问题是这是否是Swift中隐式解包Optionals的一个很好的使用。有没有更好的方法来构建我的代码以避免这种情况?

【问题讨论】:

  • 如果giveMeAThing 真的应该总是返回Thing,那么方法原型(和返回值)应该表明(ThingThing!) Swift 的主要优势之一是可选,放弃该合同是很少做的事情,如果有的话。此外,如果您跟随 Apple 的发展,他们会逐渐远离使用隐式展开的可选项,除非 Objective-C 接口绝对需要。如果某事应该始终是一个事物,那么它应该被声明为这样。如果某事物可能是事物,则应将其声明为事物?新代码不应该使用Thing!
  • 这也是我的直觉(我知道是否可以返回 nil,它不应该被隐式解包),但编译器显然不会忽略我遗漏回报的事实。隐式展开的 Optional 对我来说总是很难看。
  • 查看 matts 答案,声明它返回 Thing 并使用 assert(或类似的东西)来处理“这永远不会发生”的情况。
  • 是的,fatalError 是我需要的,所以我使用它实现了这个功能。

标签: swift optional


【解决方案1】:

您可能缺少的拼图是@noreturn。如果您将函数声明为@noreturn,如果您不履行周围的合同,编译器将放弃任何投诉。因此,您可以调用这样的方法并 not 返回 any 值,编译器不会抱怨,因为它知道我们无论如何都会死。例如,fatalErrorabort 就是这样声明的。

因此,以下是合法的:

func f() -> String {
    fatalError("oooooops")
}

即使我们未能履行返回值的合同,它也会编译,因为@noreturn(在fatalError 的声明中)撕毁合同并将碎片冲入马桶。

解决同一问题的另一种可能方法是使用assert。如果不满足条件,这会为您崩溃和燃烧。所以,在你的例子中:

func giveMeAThing() -> Thing {
    assert(!possibleErrorCase(), "gaaaaah!") // crash and burn if error case
    return createAThingForSure()
}

缺点是默认情况下,所有断言在运输应用程序中都会成功。但这在开发过程中很棒,毕竟您的运输应用程序不应该崩溃和烧毁。

【讨论】:

  • 这正是我所需要的。我想我现在正在阅读属性,看起来这可能非常有用......
  • 正如马特所指出的,@noreturn 是答案的一部分。但是,它应该很少使用(也许永远不会在应用程序级别),而是应该使用已经标记的系统功能之一(在本例中为 fatalError)。
  • @David 我同意。如果他真的要崩溃和燃烧,他应该打电话给fatalErrorassert 并完成它。 :) OP,你知道assert吗?
  • @Jumhyn 在我的新 Swift 教程中看到我对中止的讨论:apeth.com/swiftBook/ch05.html#_aborting
  • 我现在正在使用 fatalError,只是将它包装在另一个函数中以提供有关崩溃的更多信息。我确实知道断言,但我的印象是它仅用于调试目的,而不是手动触发关闭。我正在编写一个没有发布计划的命令行应用程序,而不是一个崩溃严重违反 HIG 的 App Store 应用程序。
【解决方案2】:

我宁愿这样写

func giveMeAThing() -> Thing! {
    if possibleErrorCase() {
        crashAndBurn() // I assume this will not return anyhow
    }
    return createAThingForSure()
}

但这可能只是品味问题。

【讨论】:

  • 实际上,这似乎更好,因为它实际上根本不需要隐式展开的可选选项。这是我愚蠢地没有想到的一个很好的重构,因为我的实际代码更接近if canCreateAThing(),并且检查肯定的情况更有意义。谢谢!
【解决方案3】:

您不需要隐式展开的可选项,因为您不希望第二种情况返回任何值。

正如评论者所说,在失败的情况下使用fatalError

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-26
    • 1970-01-01
    • 2017-01-30
    • 1970-01-01
    相关资源
    最近更新 更多