当前位置: 首页 > news >正文

【Rust】字符串(String 与 str) 详解

Rust 提供两种主要字符串类型:String(可变,拥有所有权)和&str(不可变,借用)。

1.字符串基础

创建字符串

// 多种创建方式lets1=String::new();// 空字符串lets2="初始内容".to_string();// &str 转 Stringlets3=String::from("Hello");// from 方法lets4="字面量".to_owned();// to_owned(克隆)// 字符串字面量(&'static str)letliteral:&str="我是字面量";

更新字符串

letmuts=String::new();// 追加字符s.push('H');// "H"s.push_str("ello");// "Hello"// 拼接lets1=String::from("Hello, ");lets2=String::from("World!");lets3=s1+&s2;// s1被消耗,s3 = "Hello, World!"// 格式拼接lets4=format!("{}{}","Hi, ","Rust!");// "Hi, Rust!"

2.字符串操作

访问内容

lets=String::from("你好,世界");// 按字节访问(UTF-8编码)forbyteins.bytes(){println!("{}",byte);// UTF-8字节序列}// 按字符访问(Unicode标量值)forchins.chars(){println!("{}",ch);// '你', '好', ',', '世', '界'}// 字符迭代器方法letchar_count=s.chars().count();// 字符数:5letbyte_len=s.len();// 字节数:15(中文3字节/字符)

切片操作

lets=String::from("Hello, World!");// 创建字符串切片lethello=&s[0..5];// "Hello"letworld=&s[7..12];// "World"// 小心!必须按字符边界切片// let bad = &s[0..1]; // 对多字节字符会panic!// 安全切片方法ifs.is_char_boundary(3){letslice=&s[0..3];// 安全切片}

3.字符串方法

查询与检查

lets=String::from("Hello Rust");// 长度信息letbyte_len=s.len();// 字节长度letis_empty=s.is_empty();// 是否为空// 包含检查lethas_hello=s.contains("Hello");// trueletstarts=s.starts_with("He");// trueletends=s.ends_with("Rust");// true// 查找letfind_idx=s.find("Rust");// Some(6)letrfind_idx=s.rfind('l');// Some(3)(从右向左)

修改操作

letmuts=String::from("Hello World");// 替换lets1=s.replace("World","Rust");// 新字符串:"Hello Rust"s.replace_range(6..11,"Rust");// 原地替换:"Hello Rust"// 删除s.remove(5);// 移除索引5的字符(',')s.pop();// 移除最后一个字符s.truncate(5);// 截断到前5个字符s.clear();// 清空字符串// 插入s.insert(5,',');// 在索引5插入字符s.insert_str(0,"Prefix ");// 插入字符串

4.字符串转换

类型转换

// String ↔ &strletstring=String::from("hello");letstr_slice:&str=&string;// 自动解引用letowned:String=str_slice.to_string();// 数字转字符串letnum_str=42.to_string();// "42"letfloat_str=format!("{:.2}",3.14159);// "3.14"// 字符串转数字letnum:i32="42".parse().unwrap();// 42letnum_result:Result<i32,_>="42".parse();// Ok(42)

字符编码

// UTF-8 编码/解码lets="🦀 Rust";// 包含emoji// 获取UTF-8字节letbytes=s.as_bytes();// &[u8]// 从字节创建(需要有效UTF-8)letfrom_bytes=String::from_utf8(bytes.to_vec());// 处理无效UTF-8letlossy=String::from_utf8_lossy(b"Hello\xFFWorld");// "Hello�World"(替换无效字节)

5.字符串格式化

format! 宏

// 基本格式化lets=format!("{} + {} = {}",1,2,3);// "1 + 2 = 3"// 控制格式letpi=format!("PI: {:.3}",3.14159);// "PI: 3.142"lethex=format!("0x{:X}",255);// "0xFF"letbin=format!("{:b}",10);// "1010"// 位置参数lets=format!("{1} {0}","World","Hello");// "Hello World"// 命名参数lets=format!("{name} is {age}",name="Alice",age=30);

其他格式化宏

print!("Hello");// 打印不换行println!("World");// 打印换行eprint!("Error");// 标准错误打印eprintln!("Error with newline");lets=format!("Debug: {:?}",vec![1,2,3]);// 调试格式lets=format!("Pretty: {:#?}",vec![1,2,3]);// 美化调试

6.字符串性能优化

预分配容量

// 避免重复分配letmuts=String::with_capacity(100);// 预分配100字节s.push_str("Hello");s.push_str(" World");println!("长度: {}, 容量: {}",s.len(),s.capacity());// 长度: 11, 容量: 100(无需重新分配)

字符串重用

// 复用String缓冲区letmuts=String::new();foriin0..10{s.clear();// 清空内容,保留容量s.push_str(&format!("Item {}",i));// 处理s...}

使用Cow(写时复制)

usestd::borrow::Cow;fnprocess(input:&str)->Cow<str>{ifinput.contains("bad"){Cow::Owned(input.replace("bad","good"))// 需要时克隆}else{Cow::Borrowed(input)// 直接借用}}letresult=process("hello");// Cow::Borrowed("hello")letresult2=process("bad word");// Cow::Owned("good word")

7.常用字符串模式

字符串分割

lets="apple,banana,orange";// 按分隔符分割letfruits:Vec<&str>=s.split(',').collect();// ["apple", "banana", "orange"]// 保留分隔符letparts:Vec<&str>=s.split_inclusive(',').collect();// ["apple,", "banana,", "orange"]// 多分隔符lets2="apple, banana; orange";letfruits2:Vec<&str>=s2.split([',',';',' ']).collect();// 行分割lettext="line1\nline2\r\nline3";letlines:Vec<&str>=text.lines().collect();

字符串修剪

lets=" Hello Rust! \n";lettrimmed=s.trim();// "Hello Rust!"(移除两端空白)letleft_trimmed=s.trim_start();// "Hello Rust! \n"letright_trimmed=s.trim_end();// " Hello Rust!"// 自定义修剪字符lets2="***Hello***";lettrimmed2=s2.trim_matches('*');// "Hello"

大小写转换

lets="Hello Rust";letupper=s.to_uppercase();// "HELLO RUST"letlower=s.to_lowercase();// "hello rust"// 首字母大写fncapitalize(s:&str)->String{letmutchars=s.chars();matchchars.next(){None=>String::new(),Some(first)=>first.to_uppercase().chain(chars).collect(),}}letcap=capitalize("hello");// "Hello"

8.字符串与集合

字符串向量

// 字符串集合letwords=vec!["hello","world","rust"].into_iter().map(|s|s.to_string()).collect::<Vec<String>>();// 连接字符串letsentence=words.join(" ");// "hello world rust"// 拼接多个字符串letconcatenated=["foo","bar","baz"].concat();// "foobarbaz"

字符处理

lets="Hello 世界";// 字符统计letchar_count=s.chars().count();// 7letgrapheme_count=s.chars().count();// 注意:可能不是字形簇数// 字符位置ifletSome(pos)=s.char_indices().find(|(_,ch)|*ch=='世').map(|(i,_)|i){println!("'世'在位置 {}",pos);// 输出位置}

9.字符串与I/O

文件读写

usestd::fs;usestd::io::{self,Write,BufRead};// 读取文件为字符串letcontent=fs::read_to_string("file.txt")?;// 写入字符串到文件fs::write("output.txt","Hello World")?;// 逐行读取letfile=fs::File::open("file.txt")?;letreader=io::BufReader::new(file);forlineinreader.lines(){letline=line?;println!("{}",line);}

用户输入

usestd::io;letmutinput=String::new();println!("请输入:");io::stdin().read_line(&mutinput)// 读取一行.expect("读取失败");lettrimmed=input.trim();// 移除换行符println!("你输入了: {}",trimmed);

10.字符串最佳实践

选择指南

  1. 函数参数:优先使用&str而非&String
  2. 返回类型:需要所有权时用String,否则考虑Cow<str>
  3. 性能敏感:预分配容量,避免重复分配
  4. 国际文本:使用chars()而非字节索引

常见错误避免

// ❌ 错误:多字节字符切片// let s = "你好";// let slice = &s[0..1]; // panic!// ✅ 正确:使用字符迭代lets="你好";ifletSome(first_char)=s.chars().next(){println!("首字符: {}",first_char);}// ❌ 避免:不必要的String分配fnbad_greeting(name:&String)->String{format!("Hello, {}",name)// 可以接受&str}// ✅ 改进:使用&str参数fngood_greeting(name:&str)->String{format!("Hello, {}",name)}

String vs &str 总结

特性String&str
所有权拥有数据借用数据
可变性可变不可变
内存位置栈、堆或静态内存
大小动态编译时已知
性能有分配开销无分配开销

核心原则

  • 需要修改或拥有字符串时使用String
  • 只读引用时使用&str
  • 函数参数优先接受&str以兼容两者
  • 使用to_string()into()进行必要转换

Rust的字符串设计确保了内存安全和UTF-8编码正确性,虽然增加了复杂性,但提供了强大的安全保证。

http://www.jsqmd.com/news/129010/

相关文章:

  • 2、探秘云计算:概念、历史、特性与服务
  • 快速理解:IPC网表在Altium Designer与PCB板生产厂家间的应用
  • Open-AutoGLM部署性能提升300%的秘密武器,你真的会用吗?
  • 南山世博特系统门窗适合家庭使用吗、实力与技术解析全指南 - 工业品牌热点
  • 【2025最新】基于SpringBoot+Vue的乡村政务办公系统管理系统源码+MyBatis+MySQL
  • 10、Windows Azure服务运行时API与角色使用指南
  • 为什么顶级团队都在悄悄测试 Open-AutoGLM 沉思浏览器?(内部资料流出)
  • LangFlow支持哪些模型?主流大模型兼容性全面测试报告
  • 从AI风控大会看数美科技博弈黑产之道:用AI对抗AI、用魔法打败魔法
  • 2025年靠谱哈尔滨暖气片安装企业排行榜,新测评精选公司推荐 - 工业推荐榜
  • 智谱Open-AutoGLM部署倒计时:如何在24小时内完成生产环境上线?
  • 为什么你的Open-AutoGLM还没封装成SDK?这5个关键步骤你必须掌握
  • 企业级校园失物招领系统管理系统源码|SpringBoot+Vue+MyBatis架构+MySQL数据库【完整版】
  • LangFlow支持Webhooks吗?实现外部系统联动
  • 2025年哈尔滨散热器品牌推荐:哪家散热器服务靠谱? - myqiye
  • 仅限内部人员知晓的Open-AutoGLM测试版Web地址泄露(速看)
  • 字节火山引擎合作前景:联合推出面向企业的AI知识套件
  • 通义千问Qwen整合指南:阿里系模型的最佳实践
  • 你不能错过的提示工程架构师提示缓存机制设计秘籍大公开
  • 壁仞BR100架构分析:高带宽内存对anything-llm的影响
  • AUTOSAR详细介绍:从零实现汽车网关系统
  • XDMA写合并机制优化内存访问性能研究
  • 提升AI开发效率:LangFlow让你像搭积木一样构建LLM流程
  • 手把手教你获取Open-AutoGLM API地址,90%开发者都不知道的隐藏通道
  • 景嘉微JM9系列评估:军规级图形处理器转AI计算的可行性
  • Open-AutoGLM或将引爆AI圈:4个信号表明它正在起飞
  • 基于anything-llm的智慧城市政策咨询服务平台构想
  • 适用于多种IDE的STLink驱动安装与烧录兼容性指南
  • anything-llm全面解析:为什么它是最佳个人AI助手?
  • 从模型到API:Open-AutoGLM转SDK的完整链路解析(含代码模板)