Swift

字符串与字符

理解 Swift 字符串的 Unicode 模型、内存管理机制,以及 Swift 6 时代的现代字符串处理技术(RegexBuilder)和并发安全性。

Swift 的 String 类型是现代编程语言中对文本处理最严谨、最强大的实现之一。它不仅完全兼容 Unicode 标准,还通过值语义和写时复制(CoW)保证了高性能与安全性。本文将从底层原理到 Swift 6 的最新特性,带你全面掌握 Swift 字符串。

字符串基础 (String Basics)

字面量

除了常规的双引号,Swift 还支持多行字符串和扩展分隔符。

// 多行字符串
let xml = """
<root>
    <user>Alice</user>
</root>
"""

// 扩展分隔符(无需转义引号)
let json = #"{ "name": "Bob" }"#

初始化

String 是结构体,初始化开销极低。

let empty = ""
let repeated = String(repeating: "A", count: 5) // "AAAAA"

字符与 Unicode (Characters & Unicode)

Swift 的 StringCharacter 的集合。理解 Character 是理解 Swift 字符串的关键。

扩展字素簇 (Extended Grapheme Clusters)

Swift 的 Character 代表一个人类可读的“字符”,无论它由多少个 Unicode 标量组成。例如,é 可以是一个标量,也可以是 e 加上重音符组合而成,在 Swift 中它们被视为同一个字符。

let eAcute: Character = "\u{E9}"                         // é
let combinedEAcute: Character = "\u{65}\u{301}"          // e + ́
// 两者相等,且 count 均为 1

这种设计虽然增加了底层复杂度,但保证了文本处理的逻辑正确性。

字符串操作 (String Manipulation)

索引 (Indices)

由于字符长度不固定,Swift 不支持整数索引(str[0]),而是使用 String.Index

let greeting = "Hello"
let start = greeting.startIndex
let end = greeting.index(before: greeting.endIndex)
let char = greeting[start] // "H"

插入与删除

var welcome = "hello"
welcome.insert("!", at: welcome.endIndex)
welcome.remove(at: welcome.index(before: welcome.endIndex))

子字符串 (Substrings)

当你对字符串进行切片时,得到的是 Substring 类型。

let full = "Hello, World"
let index = full.firstIndex(of: ",") ?? full.endIndex
let sub = full[..<index] // "Hello" (类型为 Substring)

内存共享Substring 重用原 String 的内存,极其高效。但这也意味着如果长期持有子串,原字符串的内存无法释放。因此,若需长期存储,应将其转换为 String

let newString = String(sub) // 复制内存,释放原字符串引用

现代字符串处理 (Regex & Swift 6)

Swift 5.7 引入了原生的正则表达式支持,并在后续版本中不断完善。

RegexBuilder

使用声明式语法构建正则表达式,可读性极高。

import RegexBuilder

let search = Regex {
    OneOrMore(.digit)
    "@"
    OneOrMore(.word)
}

let input = "Contact: 123@example"
if let match = input.firstMatch(of: search) {
    print(match.0) // "123@example"
}

Regex 字面量

let regex = /[a-z0-9]+@[a-z]+\.[a-z]{2,}/

性能与并发 (Performance & Concurrency)

UTF-8 视图

Swift 字符串底层默认使用 UTF-8 编码。通过 utf8 视图访问字节数据非常高效,常用于网络传输或底层解析。

let data = "Hello".utf8 // 无需拷贝

Sendable 与并发

String 是值类型,天然遵循 Sendable 协议。在 Swift 6 的严格并发检查下,你可以放心地在 Actor 之间传递字符串,无需担心数据竞争。

actor Logger {
    func log(_ message: String) {
        print(message)
    }
}
// String 传递是安全的(发生拷贝)

总结

Swift 的字符串设计在正确性(Unicode)和性能(CoW、UTF-8)之间取得了极佳的平衡。结合现代的 RegexBuilder 和 Swift 6 的并发特性,处理文本变得既优雅又高效。

在 GitHub 上编辑

上次更新于