news 2026/3/11 1:41:37

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【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编码正确性,虽然增加了复杂性,但提供了强大的安全保证。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/5 19:53:22

LangFlow中的留存率提升策略:精准推送与干预

LangFlow中的留存率提升策略&#xff1a;精准推送与干预 在用户增长竞争日趋激烈的今天&#xff0c;一个产品的成败往往不取决于它能吸引多少新用户&#xff0c;而在于能否留住他们。无论是教育平台、电商平台还是SaaS工具&#xff0c;高流失率始终是悬在运营团队头顶的达摩克利…

作者头像 李华
网站建设 2026/3/10 23:37:05

从混乱到清晰:AI架构师的实验数据清洗技巧

从混乱到清晰:AI架构师的实验数据清洗技巧 图1:数据清洗在AI项目中的核心地位与流程概览 章节一:数据清洗的基础理论与重要性 1.1 核心概念 数据清洗(Data Cleaning),也称为数据清理或数据净化,是指识别、纠正或移除数据集中存在的不准确、不完整、不一致、重复或无关…

作者头像 李华
网站建设 2026/3/4 11:58:09

17、Windows Azure Blob 存储服务全解析

Windows Azure Blob 存储服务全解析 1. 定价模式 Windows Azure 存储服务的定价规则较为清晰。每月每存储 1GB 数据收费 0.15 美元,每 10000 次存储事务收费 0.01 美元,数据传入带宽每 GB 收费 0.10 美元,数据传出带宽每 GB 收费 0.15 美元。 这种定价模式适用于 Windows…

作者头像 李华
网站建设 2026/3/3 13:13:49

【独家披露】某头部AI公司内部使用的Open-AutoGLM部署手册流出

第一章&#xff1a;Open-AutoGLM部署概述Open-AutoGLM 是一个开源的自动化大语言模型推理服务框架&#xff0c;专为高效部署和管理 GLM 系列模型而设计。它支持多种后端运行时&#xff08;如 vLLM、HuggingFace Transformers&#xff09;和灵活的 API 接口封装&#xff0c;适用…

作者头像 李华
网站建设 2026/3/8 22:35:37

28、探索全文搜索与数据建模

探索全文搜索与数据建模 1. 添加迷你控制台 为了能够测试不同的文本文件并搜索各种术语,我们需要添加一个迷你控制台。将 Program.cs 替换为以下代码: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using…

作者头像 李华
网站建设 2026/3/10 10:32:45

为什么开发者都在用anything-llm镜像做RAG应用?

为什么开发者都在用 anything-llm 镜像做 RAG 应用&#xff1f; 在大模型热潮席卷各行各业的今天&#xff0c;越来越多团队开始尝试将 LLM 引入实际业务——从智能客服到内部知识问答&#xff0c;从个人助手到企业大脑。但很快就会遇到一个现实问题&#xff1a;通义千问、GPT …

作者头像 李华