Rust编程:字符串处理、所有权与特征实现
立即解锁
发布时间: 2025-09-05 00:58:59 阅读量: 18 订阅数: 63 AIGC 


Rust Web开发实战
# Rust编程:字符串处理、所有权与特征实现
## 1. 离线浏览Rust文档
在火车、飞机上,或者想在本地访问Rust文档,可以通过`rustup`安装文档组件:
```bash
$ rustup components rust-docs
```
之后,可以在默认浏览器中打开标准库文档:
```bash
$ rustup doc --std
```
也可以从代码库生成文档,这将包含所有Cargo依赖项:
```bash
$ cargo doc --open
```
即使没有为定义的结构体和函数显式创建文档,生成的文档也会包含它们。
## 2. Rust中的字符串处理
### 2.1 String与&str的区别
在Rust中,`String`(https://doc.rust-lang.org/std/string/struct.String.html)和`&str`(https://doc.rust-lang.org/std/primitive.str.html)的主要区别在于`String`是可调整大小的。`String`是字节的集合,实现为向量,其定义如下:
```rust
// Source: https://doc.rust-lang.org/src/alloc/string.rs.html#294-296
pub struct String {
vec: Vec<u8>,
}
```
`String`可以通过`String::from("popcorn")`创建,并且创建后可以修改。而`&str`(字符串字面量)是`u8`值(文本)的表示,不能修改,可以将其视为指向底层字符串的固定大小窗口。
简单总结使用场景:
- 如果需要拥有并修改文本,创建`String`。
- 只需要底层文本的“视图”时,使用`&str`。
- 创建新的数据类型(结构体)时,通常使用`String`作为字段类型。
- 在函数中处理文本时,通常使用`&str`。
### 2.2 栈与堆
操作系统为变量和函数分配内存,有栈和堆两个概念:
- 栈通常由程序控制,每个线程有自己的栈,存储简单指令或变量,固定大小的内容可以存储在栈上。
- 堆更独特(可能有多个堆),操作堆的成本更高。数据没有固定大小,可能分散在多个块中,读取时间可能更长。
### 2.3 str类型
`&str`去掉`&`就是`str`,它是不可变的UTF - 8字节序列,没有固定长度,通常通过指针处理。引用Rust文档:“`str`类型,也称为‘字符串切片’,是最原始的字符串类型,通常以借用形式`&str`出现”(https://doc.rust-lang.org/std/primitive.str.html)。
## 3. 所有权与借用
### 3.1 所有权概念
Rust引入所有权概念,以安全地管理内存,避免使用垃圾回收器或依赖开发者的大量谨慎操作。
### 3.2 代码示例分析
#### 3.2.1 分配&str值
```rust
fn main() {
let x = "hello";
let y = x;
println!("{}", x);
}
```
运行此程序,会在控制台打印“hello”。
#### 3.2.2 分配String值
```rust
fn main() {
let x = String::from("hello");
let y = x;
println!("{}", x);
}
```
运行此程序会报错:
```plaintext
error[E0382]: borrow of moved value: `x`
--> src/main.rs:5:20
|
2 | let x = String::from("hello");
| - move occurs because `x` has type `String`, which does not implement the `Copy` trait
3 | let y = x;
| - value moved here
4 |
5 | println!("{}", x);
| ^ value borrowed here after move
```
原因是`&str`是固定大小的值,可以存储在栈上,赋值时可以简单复制。而`String`更复杂,创建后可以更改,为确保只有一个唯一的变量拥有该值,Rust将所有权从`x`转移到`y`,`x`超出作用域并调用`drop()`方法。
### 3.3 通过引用传递变量
在Rust中,可以通过引用传递变量,函数借用底层数据的所有权,处理完成后将所有权返回给调用者。示例代码如下:
```rust
fn main() {
let mut address = String::from("Street 1"); #A
address_checker(&mut address); #B
println!("{}", address); #E
}
fn address_checker(address: &mut String) { #C
address.push_str(", 1234 Kingston"); #D
}
```
- #A:声明一个可变变量并赋值为`String`。
- #B:将地址的可变引用传递给函数。
- #C:函数参数声明为可变引用。
- #D:`push_str()`方法直接修改`String`。
- #E:打印更新后的地址。
以下是一个简单的mermaid流程图,展示所有权转移过程:
```mermaid
graph LR
A[变量x拥有值] --> B[将所有权转移给变量y]
B --> C[x超出作用域,调用drop()]
```
## 4. 使用和实现特征
### 4.1 ToString特征
为了解决编译器期望`QuestionId`而得到`&str`的错误,我们可以使用`ToString`特征将`&str`转换为`String`。示例代码如下:
```rust
// ch_02/src/main.rs
struct Question {
id: QuestionId,
title: String,
content: String,
tags: Option<Vec<String>>,
}
struct QuestionId(String);
impl Question {
fn new(id: QuestionId, title: String, content: String, tags: Option<Vec<String>>) -> Self {
Question {
id,
title,
content,
tags,
```
0
0
复制全文
相关推荐










