文章目录
- 0.前言
- 1.核心定义
- 2.字符串 slice 的两种常见来源
- 3.String vs &str
- 4.示例代码
- 5.切片索引注意事项
- 6.为什么需要两种字符串类型?
- 7.总结
- 参考文献
0.前言
在 Rust 中,字符串 slice(&str)是一个对 UTF-8 编码的字符串数据段的不可变引用。它是 Rust 核心字符串类型之一,用于在不拥有数据所有权的情况下,高效地访问字符串的一部分或全部。
1.核心定义
- 语法:
&str - 本质:一个胖指针(fat pointer),包含两部分:
- 指向底层 UTF-8 字节序列的指针。
- 字符串的长度(单位是字节,不是字符数)。
- 内存位置:可以指向静态内存(如字符串字面量)、堆内存(如
String的某一部分)或栈内存(极少见)。 - 可变性:不可变,不能修改其指向的内容。
2.字符串 slice 的两种常见来源
| 来源 | 示例 | 说明 |
|---|---|---|
| 字符串字面量 | let s: &str = "Hello, world!"; | 字面量类型是&'static str,指向可执行文件的只读数据段。 |
从String借用 | let s = String::from("hello");let slice: &str = &s; | String实现了Deref<Target=str>,因此&String可自动转换为&str。 |
从String切片 | let slice = &s[0..4]; | 获取String中某一段字节的视图(注意索引必须是 UTF-8 字符边界)。 |
3.String vs &str
| 特性 | String | &str |
|---|---|---|
| 所有权 | 拥有数据所有权 | 借用数据(无所有权) |
| 内存位置 | 堆(可动态增长) | 可指向静态内存、堆或栈的一部分 |
| 可变性 | ✅ 可修改(如push_str) | ❌ 不可变 |
| 内部结构 | Vec<u8>(指针、长度、容量) | 胖指针(指针、长度) |
| 使用场景 | 需要拥有、修改或传递字符串数据时 | 需要只读访问字符串、函数参数等 |
4.示例代码
fnmain(){// 1. 字符串字面量(&'static str)lethello:&str="Hello";// 指向静态内存// 2. 从 String 借用为 &strlets=String::from("world");letworld:&str=&s;// 自动解引用强制转换// 3. 字符串 slice 切片(从 String 中获取一部分)letslice:&str=&s[0..2];// "wo"(取前两个字节)println!("slice: {}",slice);// 4. 字符串 slice 可以连接,但需要转换为 Stringletcombined=format!("{} {}",hello,world);println!("{}",combined);// "Hello world"}5.切片索引注意事项
字符串 slice 的索引必须按字节来,且必须落在 UTF-8 字符的边界上。否则程序会panic。
lets="你好";// let slice = &s[0..1]; // ❌ 运行时 panic!因为 '你' 占 3 个字节,索引 1 在字符中间letslice=&s[0..3];// ✅ "你"(三字节)println!("{}",slice);若需要按字符操作,应使用.chars()方法。
6.为什么需要两种字符串类型?
Rust 通过分离String(拥有所有权的可变字符串)和&str(借用的不可变视图),实现了:
- 内存安全:
&str的借用生命周期被编译器检查,避免悬垂引用。 - 零成本抽象:字符串 slice 不会复制数据,只创建视图。
- 高效的 API 设计:函数参数用
&str可以同时接受String和&str,无需额外转换。
fngreet(name:&str){println!("Hello, {}!",name);}fnmain(){letname1="Alice";// &strletname2=String::from("Bob");// Stringgreet(name1);// ✅ 直接传 &strgreet(&name2);// ✅ 传 &String(自动转为 &str)}7.总结
&str是字符串的只读视图,不拥有数据,指向一段 UTF-8 编码的字节。- 字符串字面量的类型是
&'static str。 - 可通过
&String或&s[start..end]获得&str。 - 它作为函数参数非常灵活,是 Rust 字符串处理的首选类型。
- 切片索引需按字节进行,且必须位于字符边界。
如果你希望进一步了解 UTF-8 编码边界和按字符操作的方法,或是str类型与[u8]的异同,我可以继续为你解释。
参考文献
Rust 程序设计语言中文版