使用Swift字符串可选链接

时间:2016-08-01 13:06:32

标签: swift string optional

使用可选链接,如果我有一个Swift变量

var s: String?

可能包含nil,或者包含在Optional中的String。所以,我尝试了这个来获得它的长度:

let count = s?.characters?.count ?? 0

然而,编译器想要这个:

let count = s?.characters.count ?? 0

我对可选链接的理解是,一旦开始在虚线表达式中使用?.,其余属性都是可选的,通常由?.访问,而不是.

所以,我进一步挖了一下并在操场上试了一下:

var s: String? = "Foo"
print(s?.characters)
// Output: Optional(Swift.String.CharacterView(_core: Swift._StringCore(_baseAddress: 0x00000001145e893f, _countAndFlags: 3, _owner: nil)))

结果表明s?.characters确实是一个Optional实例,表明s?.characters.count应该是非法的。

有人可以帮我理解这种情况吗?

2 个答案:

答案 0 :(得分:5)

当你说:

  

我对可选链接的理解是,一旦开始在虚线表达式中使用?.,其余属性都是可选的,通常由?.访问,而不是.

我会说你几乎就在那里。

并非所有属性都是可选的,原始调用是可选的,因此看起来其他属性是可选的。

characters不是可选属性,也不是count,但您调用它的值是可选的。如果有值,则characterscount属性将返回一个值;否则,返回nil。正因为如此,s?.characters.count的结果会返回Int?

如果其中一个属性是可选的,那么您需要向其添加?,但是,在您的情况下,它们不是。所以你没有。

编辑以下评论

来自评论:

  

我仍然觉得s?.characters.count(s?.characters)?.count编译都很奇怪,但(s?.characters).count却没有。为什么第一个和最后一个表达式之间存在差异?

我会在这里尝试回答,其中有更多空间而不是评论栏:

s?.characters.count

如果s为nil,则整个表达式返回nil,否则返回Int。因此返回类型为Int?

(s?.characters).count // Won’t compile

打破这种情况:如果snil,则(s?.characters)nil,因此我们无法在其上调用count

为了在count上调用(s?.characters)属性,表达式需要可选地解包,即写成:

(s?.characters)?.count

已编辑以进一步添加

我能解释的最好的方法是使用这个游乐场代码:

let s: String? = "hello"

s?.characters.count
(s?.characters)?.count
(s)?.characters.count
((s)?.characters)?.count

// s?.characters.count
func method1(s: String?) -> Int? {
    guard let s = s else { return nil }

    return s.characters.count
}

// (s?.characters).count
func method2(s: String?) -> Int? {
    guard let c = s?.characters else { return nil }

    return c.count
}

method1(s)
method2(s)

答案 1 :(得分:2)

在Swift-users邮件列表中,Ingo Maier非常友好地指出了Swift语言规范中的section on optional chaining expressions,其中指出:

  

如果包含可选链接表达式的后缀表达式嵌套在其他后缀表达式中,则只有最外层表达式返回可选类型。

继续举例:

var c: SomeClass?
var result: Bool? = c?.property.performAction()

这解释了为什么编译器在上面的示例中需要 s?.characters.count ,我认为它回答了原始问题。然而,正如@Martin R在评论中观察到的那样,编译器对这两个表达式的不同处理方式仍然存在一个谜:

s?.characters.count
(s?.characters).count

如果我正确阅读规范,那么子表达式

(s?.characters) 

"嵌套在"整体后缀表达

(s?.characters).count

因此应该与非括号版本一样对待。但这是一个单独的问题。

感谢大家的贡献!