文章目录
-
-
- 字符串字面量
- 字符串(String)
- 字符串切片(&str)
- String和&str的内存布局
- Vec\<u8\>转String(String::from_utf8_lossy())
- Vec\<u8\>转String(String::from_utf8())
- 字符串和数值类型的转换
- 字符数组/列表合并为一个String
- 字符串数组/列表合并(join/concat)为一个String
- 字符串遍历,判断字符是数字还是字母
- String中追加和删除字符
- String遍历
- 大小写转换(uppercase/lowercase)
- find()查找/contains()包含
- split()分割,返回一个迭代器
- lines()按行分割
- split_ascii_whitespace()
- split_whitespace()
- starts_with()/ends_with()
- 如何高效修改String中的一个字符?
-
字符串字面量
字符串字面量和全局变量、static变量一样位于程序运行之后虚拟地址空间中的代码区。
关于虚拟地址空间,之前有一小节详细分析过:Rust 06: 变量分配在堆还是栈上 + 虚拟地址空间
const g_array: [i32; 5] = [10; 5];
static G_VAR: i32 = 1000;
#[test]
fn test09_string() {
let s: &str = "test string";
//字符串字面量,位于代码区的ROData段
println!("&str: {:p}", s);//&str: 0x7ff77e4c6b88
println!("{:p}", &g_array);//位于data段:0x7ff6c5fc6bb8
println!("{:p}", &G_VAR);//位于data段:0x7ff77e4c6200
}
字符串字面量位于代码区的ROData段,是只读(Read Only)的,在Rust代码中字符串字面量会被处理成字符串切片类型,即&str。如果想要对字符串进行追加等操作,必须先将ROData段的字符串字面量复制一份到堆上,构造一个String类型出来。
字符串(String)
String内部其实是一个Vec,是一个可变长度的类型,末尾可以追加字符。String类型和Vec<u8>类型占用24个字节。
pub struct String {
vec: Vec<u8>,
}
println!("size: {}", std::mem::size_of::<Vec<u8>>());//24
println!("size: {}", std::mem::size_of::<String>());//24
String对象的内存结构,也就是Vec<u8>的内存结构,为 8(ptr) + 8(capacity) + 8(length)。
从字符串字面量构造出一个堆上的String有多种方式:
"xxx".to_owned()方法内部掉clone(),将字符串字面量从ROData区复制一份到堆上,并返回堆上数据的所有权;String::from("xxx")内部实际调用的是"xxx".to_owned();"xxx".to_string()内部实际调用的是String::from(“xxx”);
也就是说,下面3种方式最终都是调用了clone():
let s1: String = "Hello Rust!".to_owned();
let s2: String = String::from("Hello Rust!");
let s3: String = "Hello Rust!".to_string();
assert_eq!(s1,s2);
assert_eq!(s2,s3);
assert_eq!(s1,s3);
println!("s1: {:p}", &s1);//s1: 0x32a62fec08
println!("s2: {:p}", &s2);//s2: 0x32a62fec20
println!("s3: {:p}", &s3);//s3: 0x32a62fec38
可以看到,&s1、&s2、&s3是3个虚拟地址比较小,互不相同的栈地址。但是,实际上他们最终指向的字符串内容本身是位于堆上。
根据以上信息,我们尝试画一下let s: String = String::from("Hello");的内存布局:

字符串切片(&str)
let s1: String = "Hello Rust!".to_owned();
let s2: &String = &s1;
let s3: &str = "Hello Rust!";
let slice1: &str = &s1[0..5];//对String类型进行切片引用
let slice2: &str = &s2[0..5];//对&String类型进行切片引用
let slice3: &str = &s3[0..5];//对&str切片类型,进行切片引用
println!("{}", slice1);
println!("{}", slice2);
println!("{}", slice3);
String和&str的内存布局
还是先来做个小测试,验证一些想法:
// String内部其实是一个Vec<u8>,是一个可变长度的类型,末尾应该可以追加字符。
println!("size: {}", std::mem

本文深入探讨了Rust语言中字符串的使用与管理,包括字符串字面量、String类型及其内部结构、字符串切片、字符串与数值类型之间的转换、字符串拼接与分割、遍历与修改等高级操作。
最低0.47元/天 解锁文章
6381

被折叠的 条评论
为什么被折叠?



