Friday Q&A 2015-11-06:为什么 Swift 中的 String API 如此
欢迎来到本期因修改了很多次稿而推迟发布的周五问答。我发现很多人在使用 Swift 时,都会抱怨 <!-- more --> 什么是字符串?在我们讨论这点之前,首先需要建立一个基本的概念。我们总是把字符串想得很肤浅,很少有人能够深入思考它的本质。深思熟虑才能有助于我们理解接下来的内容。 从概念上来说,什么是字符串呢?从表面上看,字符串就是一段文本。 (顺道讲一下,我认为不应该把这些不同的文本表述概念看作是同样的字符串类型。人类可读的文本、文件路径、SQL 查询语句,以及其他所有在概念上讲并不相同的东西,在语言表示层面上都应该被表示成不同的类型。我觉得这些概念上不同的字符串应当有不同的类型,这也能大幅减少 bug 数量。尽管我并没有发现有哪个语言或者标准库做到了这点。) 那么在底层,这些常见的「文本」概念又是怎么被表示的呢?唔,得看情况。有很多不同的解决方法。 在很多语言中,字符串是用于存放字节(bytes)的数组(array)。程序所要做的就是为这些字节赋值。这种字符串的表示方法在 C++ 中是 C 语言对于字符串的表示就比较古怪和特殊。在 C 语言中,字符串是指向一串非零字节序列(sequence of non-zero bytes)的指针,以零字节位表示字符串的结束。基本的使其实和数组一样,但是 C 语言中的字符串不能包含零字节位,并且诸如查询字符串长度这样的操作需要扫描内存。 很多新语言把字符串定义成了一串 UCS-2 或者 UTF-16 码元(code unit)的集合。Java、C# 还有 JavaScript 是其中的代表。同样,在 Objective-C 中也使用了 Cocoa 和 这种想法的一个变体就是将字符串定义成 UTF-8 码元序列,其中组成的码元是 8 位的。总体上来说和 UTF-16 的表示方法很接近,但是对于 ASCII 字符串来说,能够有更加紧凑的表示空间,而且避免了在传递字符串进入函数时,由于这些函数只接受 C 语言风格类型(也就是 UTF-8 字符串)而导致的转换。 也有些语言将字符串表示为 Unicode 码位(code point)指向的一段字符序列。Python 3 中就是这么实现的,在很多 C 语言实现中也提供了内置的 简短概括一下,一个字符串通常情况下会被当做某些特定字符(character)的序列,其中字符通常是一个字节,或者是一个 UTF-16 码元,又或者是一个 Unicode 码位。 问题将字符串表示成一段连续「字符」的序列的确很方便。你可以把字符串看作是数组(array)(通常情况下就是个数组),这样就很容易获得字符串的子串、从字符串头部或者尾部取出部分元素、删除字符串的某部分、获取字符总数,等等。 问题是我们身边遍布着 Unicode,而 Unicode 会让事情变得很复杂。简单看一个字符串的例子,看一下它是怎么工作的: aé∞ |