【问题标题】:Are implicitly unwrapped optionals truly optionals?隐式展开的可选项真的是可选项吗?
【发布时间】:2018-07-26 15:19:59
【问题描述】:

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

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

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

无法传递“字符串”类型的不可变值?作为 inout 参数

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

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

我试过someFunc(&(str?)),这让事情变得更奇怪了——然后斯威夫特抱怨道:

无法传递“字符串!”类型的不可变值作为 inout 参数”。

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

那段代码实际上是:

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

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

【问题讨论】:

  • 为什么要使用像 IUO 这样的不安全构造?
  • 可能是编译器中如何实现 IUO 的神器。
  • 我同意你的第一个例子应该按照SE-0054 规定的规则编译,事实上它不是一个错误。它确实使用最新的 4.1 快照进行编译,所以看起来它已经被修复了。
  • @Hamish 谢谢——这个问题中的例子在升级到 Xcode 9.3 后确实得到了修复。但事实证明,实际的函数调用不是inout,而是UnsafeMutablePointer,它显然仍然被破坏......?有关更新的问题,请参阅 stackoverflow.com/questions/49928472/…。

标签: swift optional inout


【解决方案1】:

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

您可以通过摆脱隐式展开的可选 (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!

我强烈推荐第一个,除非绝对必要,否则避免强制展开。

【讨论】:

  • 谢谢!就我而言,我想要一个 IUO,因为它的可选性实际上只是我正在使用的较低级别 API 的产物。像var str : CFString!; let r = LowLevelGetter(&str); assert(r == noErr); NSLog("\(str)") 这样的东西,只要没有错误,一旦获取该值就永远不会是nil。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多