如何在函数中指定参数在 Swift 中可以为零

Posted

技术标签:

【中文标题】如何在函数中指定参数在 Swift 中可以为零【英文标题】:How to specify the parameter in a function can be nil in Swift 【发布时间】:2015-06-30 20:29:24 【问题描述】:

我知道我们需要在 Swift 中将函数的参数定义为既不是隐式展开的可选参数,也不是可选参数,以使其非零。但是,我不确定隐式展开的可选或可选之间更常规的是什么。

我正在观看 WWDC 2014 Swift interoperability in depth,对幻灯片中显示的两个示例有点困惑。基本上是关于我们在定义函数时是否应该使用隐式可选参数或解包参数。


视频示例

下面是那个WWDC 2014 Swift interoperability in depth的截图(09:01) 演讲者的报价是

你再次看到这是一个隐式展开的可选,所以你可以 在这里传递一个 nil 块。

注意,这里的 urlcompletionHandler 都是隐式的未包装选项,我们可以将 nil 传入其中。一切顺利!


头文件示例

然而当我查看UIKit UITableViewCell时,我发现大部分方法都是用可选参数定义的,例如

    init(style: UITableViewCellStyle, reuseIdentifier: String?)

基本上它暗示这些参数也可以为零。

似乎 ?! 都试图提出相同的建议(可以是 nil)。

我理解 ? 意味着我们将把任何值包装成 optional 值(即使是 nil),而 ! 意味着我们将打开它如果传入的是 可选 值。但我不确定我们应该使用 ! 还是 ?。哪个是传统的?


更新

看起来来自 WWDC 2014 的视频不太正确或过时。视频截图显示了 UIDocument 头文件,它与当前的 UIKit 头文件不同。好像当时都被定义为。但现在它要么是 ? 要么是普通类型。

WWDC 2014 Swift 深度互操作性(16:25)

当前头文件

【问题讨论】:

【参考方案1】: ?Optional<T> 类型的快捷方式 !ImplicitlyUnwrappedOptional<T> 类型的快捷方式

这两种类型都实现了 NilLiteralConvertible。这意味着它们有init(nilLiteral: ()) 并且可以由Void 初始化。这可能是编译器在代码中将nil 定期分配给NilLiteralConvertible 变量的语法糖。以下是一些从编译器角度来看具有相同含义的代码行:

 let sweetOptionalInt: Int? = nil
 let semiSweetOptionalInt: Optional<Int> = nil
 let unsweetenedOptionalInt: Optional<Int> = Optional<Int>(nilLiteral: Void)

ImplicitlyUnwrappedOptional 也是如此。

所以两者都可以被nil初始化,但是这些类型的行为是不同的:

ImplicitlyUnwrappedOptional 为你做一个假设 当您执行呼叫时,已经提供了一个对象(但可能是 nil 之前),因此如果不是,则应用程序将因运行时错误而崩溃。 Optional 将要求您提供如何解包变量的信息。

至于互操作性,之前 Objective-C 没有办法表达变量的可空性。这就是为什么大多数 API 都使用 !这代表“如果你敢的话,继续前进” 最近 Apple introduced Objective-C 的可空性注释。 Apple 使用这些注释增强了他们的 API,因此现在在 Swift 中使用带有额外可空性指导的方法更容易、更安全。

【讨论】:

我认为这更接近事实。那么传统的方式是什么呢?好像是“!”前。但我猜它是“?”现在。 如果在 ObjC 中没有使用新的可空性关键字,您应该使用 !因为行为未定义,任何事情都可能发生。他们用可空性信息增强了一些旧 API,这就是为什么现在你有时间看到?或没有 ? / !完全没有。 @EthanFang 在本文末尾查看 Apple 解释了一些 API 是如何变化的。新的可空性注释之前和现在的情况 — developer.apple.com/swift/blog/?id=25 @EthanFang 您关于签名更改的更新绝对正确。可空性注释是最近才引入的,所以我们所说的 ObjC API 都在转换。 感谢您的解释和链接。现在我有了更深的了解!【参考方案2】:

你说的不太对。 “!”是“强制展开”运算符。它说“这是一个可选的,但我保证当这段代码运行时,它不会是零。”如果你错了,你就会崩溃。

如果您正在编写一个函数,该函数接受一个可以合法地为 nil 的参数,请使用“?”,这使它成为一个可选的。然后在你的函数代码中,你必须处理它为 nil 的情况。

【讨论】:

“!”是什么意思?用于装饰 parameter 类型时是否有效?肯定不是同一个运营商那里.. 感谢您的回复@duncan C。但请参考我在上面发布的视频。我和你的印象完全一样,直到我糊涂了。 正如 Nikita 在他的回答中所说,“强制展开”最好称为隐式展开。这意味着它可以包含 nil,但除非您确定它不是 nil,否则不要尝试读取实际内容。

以上是关于如何在函数中指定参数在 Swift 中可以为零的主要内容,如果未能解决你的问题,请参考以下文章

如何在python函数中指定传递的参数必须是函数[重复]

如何在类型提示中指定函数类型?

如何在 Swift 中指定要避免的范围

Postgres:如何在where语句中指定参数[重复]

如何在参数中指定两个默认日期

如何使用变量在ggplot中指定列名