Rust中字符串迭代:如何轻松遍历字符

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

Rust中字符串迭代:底层工作原理



您是否曾想过,当您写下for c in "Привет".chars()时实际发生了什么?如果您来自Python或JavaScript,那里的字符串只是字符数组,Rust可能像一位严格的老师,迫使您在每次操作前思考。这很棒!



Stack Overflow上关于"How do you iterate over a string by character"的问题获得了数千次浏览。这并非偶然。Rust中没有简单的string[i]——这是有充分理由的。让我们了解如何正确、高效且无意外地遍历字符串。



为什么Rust不允许您直接通过索引获取字符?



这一切都源于UTF-8编码。与许多语言不同,Rust将字符串存储为UTF-8格式,而非ASCII或UCS-2。这意味着一个字符可能占用1到4个字节。例如:



  • 'a' — 1字节
  • 'é' — 2字节
  • '中' — 3字节
  • '😊' — 4字节


如果Rust允许string[0],那么"😊"[0]返回的将不是表情符号,而是其字节表示的一半——垃圾数据。因此,Rust在编译器层面保护您免受此类错误的影响。



遍历字符串的主要方法



Rust提供了三种主要的迭代方法,各有其用途。选择取决于您具体需要什么:字符、字节还是字素簇。



1. 按字符迭代(char)



最常用的方法是.chars()。它返回一个Unicode字符(char类型)的迭代器。



fn main() {    let text = "Привет, мир! 🌍";        for c in text.chars() {        println!("{}", c);    }        // 输出:    // П    // р    // и    // в    // е    // т    // ,    // (空格)    // м    // и    // р    // !    // (空格)    // 🌍}


在底层,.chars()解析UTF-8字节序列并返回每个有效的字符。如果字符串中包含无效字节,迭代器可能返回std::char::REPLACEMENT_CHARACTER('�')。



重要提示:.chars()的时间复杂度为O(n)。迭代器遍历所有字节,即时解码。对于短字符串,这几乎是瞬间完成的,但对于长字符串(兆字节级别的文本),可能会比较明显。



2. 按字节迭代(bytes)



如果您需要原始字节,请使用.bytes()。这是一种快速的方法,但您得到的是字节,而不是字符。



fn main() {    let text = "Hello";        for byte in text.bytes() {        println!("{}", byte);    }        // 输出:    // 72 (H)    // 101 (e)    // 108 (l)    // 108 (l)    // 111 (o)}


对于英文文本,这等同于按字符迭代。但对于俄语或表情符号则不然。例如,"Привет"在字节表示中占用12个字节(每个字符2个字节),而"🌍"占用4个字节。



何时使用:当您处理二进制数据、协议或希望在不进行UTF-8解码的情况下获得最大性能时。



3. 按字素簇迭代(grapheme clusters)



这就更有趣了。有时,一个视觉上的"字符"由多个Unicode字符组成。例如,国家旗帜或带变音符号的字母:"é"可以表示为单个字符é(U+00E9),也可以表示为e + ◌́(U+0065 + U+0301)的组合。



要处理字素簇,需要添加crate unicode-segmentation:



// Cargo.toml// [dependencies]// unicode-segmentation = "1.10"

use unicode_segmentation::UnicodeSegmentation;

fn main() { let text = "é"; // chars() 将返回1个字符

博客

书籍推荐