隐式展开的可选值真的是可选值吗?

Are implicitly unwrapped optionals truly optionals?

在 Swift 4.0 中,以下代码无法编译:

var str: String!
func someFunc(_ s: inout String?) {}
someFunc(&str)

现在我想象 str 实际上是 String? 类型,并且 Swift 编译器似乎同意:

Cannot pass immutable value of type 'String?' as inout argument

我可以通过将变量类型更改为 String? 或将函数参数更改为 (_ s: inout String!) 来解决此问题,但我不明白为什么必须这样做。 Swift 似乎已经同意 var str : String! 是 "of type 'String?'" — 那为什么不让我在这里传递它呢?

我可以使用另一个选项来隐式展开我的变量,但仍将其传递给修改可选的函数吗?

我尝试了 someFunc(&(str?)),这只会让事情变得更奇怪 — 然后 Swift 抱怨:

Cannot pass immutable value of type 'String!' as inout argument".

所以 strString? 但不能作为 String? 传递,而 str?String!?!

该代码实际上是:

var str: String!
func someFunc(_ x: inout String!) {}
someFunc(&(str?))

所以也许 Swift 在其错误消息中错误地说明了参数的类型,而不是传递的值……或者什么?

这是一个 known bug in the swift compiler. 已在 Swift 4.1 快照中修复,因此可能会在下一个 Xcode 版本 (9.3) 中修复。

您可以通过删除 implicitly-unwrapped 可选 (IUO) 来解决这个问题,无论如何都应该避免。根据它目前是 IUO 的原因,可以:

var str: String?
func someFunc(_ x: inout String?) {}
someFunc(&str)

var tmp: String?
func someFunc(_ x: inout String?) {}
someFunc(&tmp)
let str = tmp!

我强烈推荐第一种,除非绝对必要,否则请避免使用 force-unwrapping。