为什么Swift字符串不能用整数索引

Swift中,字符串是不能使用整数索引的,比如下面的代码会报错:

let name = "Neil"
name[2]
// 'subscript(_:)' is unavailable: cannot subscript String with an Int, use a String.Index instead.

这是为什么呢? 简单的回答是:Swift认为字符串是由一个个字形群集 (grapheme clusters)组成的,字形群集的大小不固定所以不能用整数去索引 (字形群集其实就是Swift中的Character(字符)类).

我们先看看苹果是怎么定义字形群集的:

An extended grapheme cluster is a sequence of one or more Unicode scalars that (when combined) produce a single human-readable character.*

意思就是Swift中一个字符 (一个字形群集) 可以由一个或者多个unicode scalar组成. 比如:

let letterNorml = "é"

let letterCombining = "e\u{0301}"

for code in letterNorml.unicodeScalars {

 print(code.value)

}

// 233

for code in letterCombining.unicodeScalars {

 print(code.value)

}

// 101

// 769

这里了 letterNorml 字符串只有一个unicode scalar (233) 而 letterConbining 字符串有两个unicode scalar (101 和 769).

但他们是相等的:

print(letterNorml == letterCombining)  // true

他们的字符(字形群集)数量相等,都只有一个:

print(letterNorml.count)  // 1
print(letterCombining.count)  // 1

但unicode scalars的数量不同:

print(letterNorml.unicodeScalars.count)  // 1
print(letterCombining.unicodeScalars.count)  // 2

因为这样,不同的字符可能需要不同数量的unicode. 比如上面的例子, 有的字母需要两个unicodes. 有的表情甚至需要4个unicodes.

这样导致一个字符需要变长度的内存空间存储,让索引变得困难。下面解释为什么:

如果一个字符是固定长度的,比如4个字节,想要找到一个字符串中位置i的字符,只需要把字符串的起始位置加上4*i就行,时间复杂度是O(1)。

然而,如果一个字符是变长度的,那我们必须从头遍历字符串中所有的unicode scalar来确定某个字符的位置,最坏情况的时间复杂度是O(n)

由于这个原因,Swift字符串不能有整数去索引

Swift字符串的索引方法

我们需要用String.Index类型来索引字符串:

let name = "Neil"
let index = name.index(name.startIndex, offsetBy: 2)
let char = name[index]  //  i

用Range类型来获得子字符串:

let name = "Neil"

let index1 = name.index(name.startIndex, offsetBy: 1)

let index2 = name.index(name.startIndex, offsetBy: 3)

let indexRange = index1...index2

let subString = name[indexRange] // eil

你可能感兴趣的:(为什么Swift字符串不能用整数索引)