隐式解包可选项真的算是可选项吗?

3
在Swift 4.0中,以下代码无法编译:
var str: String!
func someFunc(_ s: inout String?) {}
someFunc(&str)

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

无法将不可变类型'String?'作为引用参数传递

我可以通过将变量更改为String?类型或将函数参数更改为(_s: inout String!)类型来解决这个问题,但我不明白为什么要这样做。Swift似乎已经认为var str : String!是"类型 'String?'",那么为什么它不允许我在这里传递呢?
是否有其他选项可以使我的变量隐式解包,但仍然将其传递到修改可选值的函数中? 我尝试了someFunc(&(str?)),但情况变得更奇怪了——然后Swift抱怨:

无法将不可变类型'String!'作为引用参数传递。

所以strString?,但不能作为String?传递,而str?String!?!
那段代码实际上是:
var str: String!
func someFunc(_ x: inout String!) {}
someFunc(&(str?))

也许Swift在错误信息中误将参数的类型而非传递的值进行说明……或者什么其他原因?


1
为什么要使用像IUO这样的不安全构造? - Cristik
可能是编译器实现IUO的一种产物。 - Kevin
3
我同意你的第一个例子应该符合SE-0054的规则并编译通过,但是它没有通过编译是一个错误。不过,最新的4.1快照可以编译通过,所以看起来它已经被修复了。 - Hamish
@Hamish 谢谢 - 在升级到Xcode 9.3之后,这个问题的示例确实得到了修复。但事实证明,实际的函数调用不是 inout,而是 UnsafeMutablePointer,它显然仍然存在问题...?请参见 https://dev59.com/Tarka4cB1Zd3GeqPisJZ 获取更新的问题。 - natevw
1个回答

1
这是Swift编译器中已知的一个错误Hamish在评论中表示,这个问题已经在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 - natevw

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接