rust字符与字符串:String和&str的异同

举报
数字扫地僧 发表于 2025/06/10 12:00:24 2025/06/10
【摘要】 在编程的世界里,字符串处理是绕不开的话题。而在 Rust 中,字符串有两大核心类型:String 和 &str。初次接触 Rust 的开发者,常常会对这两者感到困惑。今天,让我们深入探讨它们的异同,以便更精准地在项目中使用它们。 一、初识String和&str (一)什么是StringString 是 Rust 中的字符串类型,它是一个可变的、拥有的、 UTF-8编码的字符串。这意味着你可以...

在编程的世界里,字符串处理是绕不开的话题。而在 Rust 中,字符串有两大核心类型:String&str。初次接触 Rust 的开发者,常常会对这两者感到困惑。今天,让我们深入探讨它们的异同,以便更精准地在项目中使用它们。

一、初识String和&str

(一)什么是String

String 是 Rust 中的字符串类型,它是一个可变的、拥有的、 UTF-8编码的字符串。这意味着你可以自由地修改它,比如追加字符或截取子串。这种类型适合需要频繁修改内容的场景。

举个例子,我们创建一个 String

let mut s = String::new();
s.push_str("hello");
s.push_str(" world");
println!("{}", s); // 输出 "hello world"

这里,我们先创建了一个空的 String。接着,通过 push_str 方法追加内容。这表明 String 是可变的,能够根据需要动态调整大小。

(二)什么是&str

&str 是字符串切片,它是一个不可变的、借用的、 UTF-8编码的字符串片段。&str 通常用于表示一段已有的字符串数据,它的大小在编译时就已确定。这种类型适合只读的场景。例如,字面量字符串就是 &str 类型:

let s: &str = "hello world";

这里的 "hello world" 就是一个字符串字面量,它的类型是 &str。我们无法直接修改 s 的内容,因为它是不可变的。

(三)mermaid总结

String
可变
拥有的
UTF-8编码
&str
不可变
借用的
UTF-8编码

罗马数字列表:
I. String 适合需要频繁修改的场景。
II. &str 适合只读的场景。

二、String和&str的内存布局

(一)String的内存结构

String 在内存中是一个动态分配的数据结构,它包含三个部分:

部分 说明
指针 指向堆上实际存储的字符串数据的起始位置
长度 表示当前字符串的长度
容量 表示分配的内存容量,用于容纳未来的扩展
let mut s = String::from("hello");
s.push_str(" world");

当我们在 s 后追加 " world" 时,String 会自动在堆上分配更多内存。如果当前容量不足,它会分配一个新的更大的内存块,将原有数据复制过去,然后释放旧的内存。这种动态扩容机制使得 String 能够灵活应对内容的变化。

(二)&str的内存结构

&str 是一个指向已有字符串数据的切片,它包含两个部分:

部分 说明
指针 指向字符串数据的起始位置
长度 表示切片的长度
let s = "hello world";
let part = &s[0..5];

这里,part 是一个 &str,它指向 s 的前五个字符。由于 &str 不拥有数据,它的大小是固定的,由编译器确定。

(三)mermaid总结

String
指针
长度
容量
&str
指针
长度

罗马数字列表:
III. String 的动态扩容机制使其能够灵活应对内容变化。
IV. &str 的固定大小使其在只读场景下效率更高。

三、String和&str的转换

(一)从&str创建String

可以通过 String::fromto_string 方法将 &str 转换为 String

let s1 = "hello";
let s2 = String::from(s1);
let s3 = s1.to_string();

String::fromto_string 方法都会在堆上为字符串分配内存,并将 &str 的内容复制过去。此时,s2s3 是独立拥有的 String

(二)从String获取&str

可以通过 & 操作符将 String 转换为 &str

let s = String::from("hello world");
let s_slice: &str = &s;

这里,s_slice 是一个指向 s 内容的 &str。由于 &str 不拥有数据,它的生命周期不能超过原始的 String

(三)mermaid总结

&str
String::from
to_string
String
&
&str

罗马数字列表:
V. 从 &str 创建 String 会复制数据。
VI. 从 String 获取 &str 不会复制数据,只是创建一个视图。

四、String和&str的操作

(一)String的操作

1. 追加内容

可以通过 push_str 方法向 String 追加内容:

let mut s = String::from("hello");
s.push_str(" world");
println!("{}", s); // 输出 "hello world"

push_str 方法将内容追加到 String 的末尾。如果当前容量不足,String 会自动扩容。

2. 合并字符串

可以通过 + 运算符合并两个 String

let s1 = String::from("hello");
let s2 = String::from(" world");
let s3 = s1 + &s2;

这里,s3 是合并后的 String,而 s1 被转移给了 s3,不能再使用。

(二)&str的操作

1. 截取子串

可以通过切片语法从 &str 中截取子串:

let s = "hello world";
let sub = &s[0..5];
println!("{}", sub); // 输出 "hello"

这里,sub 是一个指向 s 前五个字符的 &str

2. 拼接字符串

可以通过 format! 宏拼接多个 &str

let s1 = "hello";
let s2 = "world";
let s3 = format!("{} {}", s1, s2);

format! 宏会创建一个新的 String,并将 s1s2 的内容复制进去。

(三)mermaid总结

String
push_str
+
&str
切片
format!

罗马数字列表:
VII. String 的操作会修改其内容。
VIII. &str 的操作不会修改原始数据。

五、性能对比

(一)内存分配

String 需要在堆上动态分配内存,这涉及到内存分配和可能的扩容操作。频繁的分配和扩容可能会带来性能开销。

&str 是栈上存储的指针和长度,它的大小是固定的,访问速度快。

(二)数据复制

&str 创建 String 会复制数据,这在大数据量时可能会消耗较多时间。

String 获取 &str 不会复制数据,只是创建一个视图。

(三)mermaid总结

String
动态分配
可能扩容
&str
栈上存储
固定大小

罗马数字列表:
IX. String 的动态分配和扩容可能带来性能开销。
X. &str 的固定大小使其访问速度快。

六、实例分析

(一)实例一:字符串拼接

1. 使用String

let mut s = String::new();
for i in 0..10 {
    s.push_str(&i.to_string());
}

这里的字符串拼接效率较低,因为每次循环都会触发 String 的追加操作,可能导致多次扩容。

2. 使用&str和format!

let mut s = String::new();
for i in 0..10 {
    s = format!("{}{}", s, i);
}

这种写法性能更差,因为每次 format! 都会创建一个新的 String,并将旧数据复制过去。

3. 更好的方法

let mut s = String::with_capacity(10);
for i in 0..10 {
    s.push_str(&i.to_string());
}

通过预先设置 String 的容量,可以避免多次扩容,提高性能。

(二)实例二:字符串截取

let s = "hello world";
let sub = &s[0..5];

这里,我们从 &str 中截取子串,不会复制数据,效率很高。

(三)mermaid总结

低效拼接
多次扩容
format!拼接
重复创建
预设容量
避免扩容
&str截取
无复制

罗马数字列表:
XI. 预设 String 容量可以避免多次扩容。
XII. &str 的截取操作效率高,无数据复制。

七、总结

在 Rust 中,String&str 各有特点:

特性 String &str
可变性 可变 不可变
生命周期 拥有数据 借用数据
内存布局 堆分配,包含指针、长度和容量 栈存储指针和长度
性能 动态操作可能带来开销 访问速度快,无复制

在开发中,根据场景选择合适的类型:

  • 需要频繁修改时,使用 String
  • 只需读取时,优先使用 &str
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。