编程与开发

Rust Unicode

Rust strings (str/String) are guaranteed valid UTF-8. char type represents a Unicode scalar value (4 bytes). Iteration via .chars() yields code points, .graphemes() requires the unicode-segmentation crate.

What is Rust Unicode Handling?

Rust takes a principled stance on Unicode: all str and String values are guaranteed to be valid UTF-8 at all times, enforced by the type system and runtime checks. This eliminates the class of bugs where a program inadvertently operates on text that is not valid Unicode. The tradeoff is that indexing into a string by position requires care — a byte index is not the same as a code point index or a grapheme cluster index.

str and String as Valid UTF-8

str is Rust's primitive string type — a slice of UTF-8-encoded bytes. String is the owned, heap-allocated version. Neither can contain invalid UTF-8:

let s: &str = "héllo";        // valid UTF-8, always
let owned: String = String::from("世界");  // valid UTF-8, always

// Compile error: cannot index by arbitrary byte position
// let c = s[1];  // ERROR: cannot index into a str

// Correct: get a character by byte offset (only at char boundaries)
let c = &s[2..4];  // byte slice — only safe at known boundaries

char as a Unicode Scalar Value

Rust's char type holds exactly one Unicode scalar value — any code point from U+0000 to U+10FFFF, excluding surrogate code points (U+D800 to U+DFFF). This is 21 bits, stored in 4 bytes (u32 internally):

let heart: char = '\u{2764}';  // ❤ HEAVY BLACK HEART
let emoji: char = '\u{1F600}'; // 😀 GRINNING FACE — valid char in Rust

heart as u32  // 10084

.chars() vs .bytes() vs .graphemes()

Rust's str exposes three levels of iteration:

let s = "café";

// bytes() — raw UTF-8 byte values
s.bytes().count();   // 5 (c=1, a=1, f=1, é=2 bytes)

// chars() — Unicode scalar values (code points)
s.chars().count();   // 4 (c, a, f, é)

// graphemes() — user-perceived characters (requires unicode-segmentation crate)
use unicode_segmentation::UnicodeSegmentation;
s.graphemes(true).count();  // 4 (same here, but differs for combined sequences)

let family = "👨‍👩‍👧";
family.chars().count();      // 5 code points (3 people + 2 ZWJ)
family.graphemes(true).count(); // 1 grapheme cluster

The unicode-segmentation crate implements UAX#29 grapheme cluster boundaries, word boundaries, and sentence boundaries. Add it to Cargo.toml:

[dependencies]
unicode-segmentation = "1.10"

Pattern Matching on chars

Rust's string methods accept closures on char for flexible searching:

let s = "hello, 世界!";

s.contains(|c: char| c.is_alphabetic());   // true
s.chars().filter(|c| c.is_uppercase()).count();  // 0

// Unicode-aware char classification
'\u{0041}'.is_uppercase()  // true (A)
'\u{0627}'.is_alphabetic() // true (Arabic Alef)
'\u{0661}'.is_numeric()    // true (Arabic-Indic digit one)

Quick Facts

Feature Detail
str / String encoding Valid UTF-8, enforced at creation
char type Unicode scalar value (not code unit), 4 bytes
Surrogates Not valid char values (compile error)
Byte iteration .bytes() — raw u8 values
Code point iteration .chars() — Unicode scalar values
Grapheme iteration .graphemes() — from unicode-segmentation crate
UAX#29 implementation unicode-segmentation crate
Unicode properties unicode-properties crate, or char methods
Normalization unicode-normalization crate (NFC, NFD, NFKC, NFKD)

相关术语

编程与开发 中的更多内容

Java Unicode

Java strings use UTF-16 internally. char is 16-bit (only BMP). For supplementary …

Python Unicode

Python 3 uses Unicode strings by default (str = UTF-8 internally via …

Unicode 正则表达式

使用Unicode属性的正则表达式模式:\p{L}(任意字母)、\p{Script=Greek}(希腊文字)、\p{Emoji},各语言和正则引擎的支持程度不同。

Unicode 转义序列

在源代码中表示Unicode字符的语法,各语言不同:\u2713(Python/Java/JS)、\u{2713}(JS/Ruby/Rust)、\U00012345(Python/C)。

不可见字符

无可见字形的字符:空白、零宽字符、控制字符和格式字符,可能引发欺骗和文本隐写等安全问题。

乱码

用错误编码解码字节时产生的乱码文本,来自日语词“文字化け”。例如:'café'以UTF-8存储但用Latin-1读取,显示为'café'。

代理对

在UTF-16中一起编码补充字符的两个16位码元(高代理U+D800–U+DBFF + 低代理U+DC00–U+DFFF),😀 = D83D DE00。

字符串

编程语言中的字符序列,内部表示各异:UTF-8(Go、Rust、新版Python)、UTF-16(Java、JavaScript、C#)或UTF-32(Python)。

字符串长度歧义

Unicode字符串的“长度”取决于计量单位:码元(JavaScript .length)、码位(Python len())或字素簇。👨‍👩‍👧‍👦 = 7个码位,1个字素。

替换字符

U+FFFD(�),解码器遇到无效字节序列时显示的字符——“解码出错”的通用符号。