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

Rust字符串

str

  • str类型是一种原生类型,str类型具有切片的所有特性,包括无固定大小和只读。
  • 因为str就是一个切片,通常会借用一个str,即&str。
  • str类型有两个字段组成,指向字符串数据的指针和长度。

字符串字面量定义在(“…”)内,是程序整个生命周期内都存在的str值。
因此字符串字面量的生命周期是静态的,表示为&'static str

字符串

  • 字符串(String)类型定义在Rust标准库中,是基于特化的向量实现的,由字符值组成。
  • 字符串和向量一样是可变的也是可增长的。
  • 字符串Striing类型包含3个字段:指向底层数组的指针、长度、容量。
    • 底层数组是分配的内存空间
    • 长度是按照utf-8编码占据的字节数
    • 容量是底层分配给数组空间的长度

创建字符串实例

  • 使用String::from(“str”)和str::to_string(),将str转成String
fn main() {let str1 = String::from("hello world1");let str2 = "hello world2".to_string();println!("{} {}",str1, str2);
}
  • 也可以通过new构造函数为String创造一个新的空字符串,然后将字符串追加进里面,前提是可变
fn main() {let mut new_str = String::new();new_str.push_str("hello world3");println!("{}",new_str);
}

如前所述,字符串是一种特殊的字符值向量,你甚至可以直接从向量创建一个字符串。

fn main() {let v = vec![65, 114, 107, 97, 110, 115, 97, 115];let str = String::from_utf8(v).unwrap();println!("{}",str);
}

在这个示例中,"Arkansas"这个码值被存储到一个向量v内,例如码值65对应的字符A,通过from_utf函数将这个向量转换成一个字符串

字符串长度

一个给定的unicode字符的长度是多少?这个问题看似简单实际上很复杂。
首先,这取决于你是指字符串的字符个数还是字节。一个utf-8字符可以用1-4个字节来描述,asscii字符,在unicode中是1字节。然而位于代码空间其他位置的字符大小可能是多个字节

  • Ascii是单字节大小
  • 希腊字符是2字节大小
  • 中文字符是3字节大小
  • 表情符号是4字节大小

对于ascii,字节长度和字符数量是相同的。而对于其他字符集可能会有所不同。len函数返回字符串中的字节数

fn main() {let str = "你好世界";println!("{}",str.len());
}

理应打印的是4,实际上却是12
要获取字符串中字符的数量,可以首先使用chars返回字符串字符的迭代器,然后在迭代器上调用count方法来统计字符数量

fn main() {let str = "你好世界";let size = str.chars().count();println!("{}",size);
}

扩展字符串

你可以扩展一个字符串String的值,但你不能扩展str类型的值。下面提供了几个方法

  • push 对于String追加char值
  • push_str 对于String追加一个str
fn main() {let mut str = String::new();str.push_str("hello world");str.push('!');println!("{}",str);
}
  • insert
  • insert_str

有时候,你可能不仅仅想在字符串末尾追加新内容,而是想将新内容插入到已有字符串中间的某个位置。

fn main() {let mut characters = "ac".to_string();characters.insert(1, 'b');println!("{}",characters);let mut numbers = "one  three".to_string();numbers.insert_str(4, "two");println!("{}", numbers);
}

字符串容量

作为特化的向量,String具有一个底层数组和一个容量。

  • 底层数组是存储字符串字符的空间,容量是底层数组的总大小,而长度则是字符串当前占用的大小。
  • 当长度超过容量时,底层数组必须重新分配并进行扩展,
    当底层数组重新分配发生时,会有性能损失。因此避免不必要的重新分配可以提供程序的性能。
fn main() {let mut str = '我'.to_string();println!("容量:{} 长度:{}",str.capacity(), str.len());str.push('是');println!("容量:{} 长度:{}",str.capacity(), str.len());str.push('谁');println!("容量:{} 长度:{}",str.capacity(), str.len());
}

上述例子将字符转换为字符串,然后每次追加一个字符,都引起字符串str的扩容,发生了两次重新分配,对应的3->8->16

如果一开始就能预估需要多大的字符值数组,那么在前面例子就可以给出更高效的写法,通过with_capacity()可以在创建字符串时手动指定容量大小

fn main() {let mut str = String::with_capacity(12);str.push('我');str.push('是');str.push('谁');println!("容量:{} 长度:{} 内容:{}",str.capacity(), str.len(), str);
}

访问字符串的值

我们知道,字符串本质上就是字符值数组,所以通过数组下标索引来访问吗?

fn main() {let str = "你好世界".to_string();let ch = str[1];
}

然后你将会得到类似这样的错误

error[E0277]: the type `str` cannot be indexed by `{integer}`

虽然错误本身是正确的,但没有解释清楚根本原因。
实际上,根本问题是: 对字符串使用索引进行访问是存在歧义的,我们无法确定索引值究竟对应的字节位置还是字符位置。没有解决这一歧义,继续这种操作会被编译器认为是不安全的。
因此,在Rust中直接通过索引来访问字符串中的字符是明确禁止的。
你可以通过字符串切片来访问String中的字符,起始索引和结束索引来表示字节位置,切片的结果是一个str

string[startIndex..endIndex]

示例

fn main() {let str = "你好世界".to_string();let ch = &str[3..=5];println!("{}", ch);
}

字符位置如下图所示
在这里插入图片描述

当尝试获取字符串切片的前两个字符,但是切片的位置是不正确的,就会引发一个panic
示例

fn main() {let str = "你好世界".to_string();let ch = &str[0..8];println!("{}", ch);
}

输出

byte index 8 is not a char boundary; it is inside '世' (bytes 6..9) of `你好世界`

在获取字符串切片之前,你可以手动调用str类型的is_char_boundary方法来确定给定索引位置是否与字符边界的开始对齐

fn main() {let str = "你好世界".to_string();println!("{}",str.is_char_boundary(0)); // trueprintln!("{}",str.is_char_boundary(1)); //false
}

字符串里的字符

字符串由字符组成,一个很有用的操作是迭代每一个字符。比如对每个字符执行某种操作、对字符进行编码、统计字符数量、或者搜索并删除包含字母e的所有单词等等。
字符串的chars方法会返回一个字符串迭代器,方便我们遍历访问字符串中的每一个字符。

fn main() {let str = "你好世界".to_string();for ch in str.chars() {println!("{}", ch);}
}

也可以使用迭代器的nth方法读取某个位置的一个字符

fn main() {let str = "你好世界".to_string();let ch1 = str.chars().nth(1).unwrap();println!("{}", ch1);}

格式化字符串

在需要&str的场合,可以借用字符串的&String来代替。这时String会继承str的所有方法,这种隐式转换的原理就是String类型为str实现了Deref trait,这种自动转换行为被称为Deref强制转换,但反过来,从str转换为String类型是不允许的

fn foo(str: &str) {println!("{}", str);
}
fn main() {let str = "hello".to_string();foo(&str);
}

格式化字符串

如果你需要创建格式化的字符串,那么可以使用format!()宏,这个宏与println!()的用法类似,不同的是,它返回一个格式化后的字符串,而不是直接输出。

fn main() {let left = 5;let right = 10;let result = format!("{}+{}={}",left, right, left+right);println!("{}",result);
}
http://www.dtcms.com/a/395596.html

相关文章:

  • 【图文详解】强化学习最新进展以及核心技术突破方向、核心技术架构
  • Linux SSH 安全加固与批量管理:密钥认证 + 自动化脚本 + OpenSSH 升级
  • 一个可以直接跑满本地带宽文件分享工具 开箱即用,可用于局域网内分享文件和文件夹
  • 探索AI无人直播技术:自动化带来的新机遇
  • Codeforces Round 1051 (Div. 2) D1题 题解记录
  • 计算机视觉、图像处理国际学术会议
  • redhat7.4升级到Oracle Linux8.10
  • PEFT库实战快速入门
  • PyTorch 核心知识手册:神经网络构建与训练基础
  • DeepSeek对数学工具的分类(2025.1.13)
  • 2025年9月打磨机器人新技术解析与常见知名品牌推荐
  • STM32开发(WiFi - ESP8266)
  • ArcGIS 车辆轨迹跟踪 视频制作 第一人称视觉跟踪
  • Ansible自动化运维平台部署
  • VGG和PyTorch 神经网络工具箱
  • Linux系统nginx(一)
  • 144g网页制作最新 144g网页在线生成方法
  • PyTorch 神经网络工具箱全面解析
  • mac-vlan 概念及题目
  • 【华为OD机考正在更新】2025年双机位A卷真题【完全原创题解 | 详细考点分类 | 不断更新题目 | 六种主流语言Py+Java+Cpp+C+Js+Go】
  • 《Muduo网络库:基于Muduo的网络服务器编程示例》
  • 详解JNI JNA!
  • C# 获取docx文档页数的古怪方法
  • 算法题(215):奶牛飞盘
  • Ubuntu 安装与使用C++ onnxruntime库
  • Ubuntu 部署 Zabbix 6.0 LTS 监控平台
  • 基于springboot家政、上门服务、Java源码系统功能结构
  • 从 “纸笔清单” 到全栈引擎:数据填报与类 Excel 控件如何重塑企业效率曲线
  • FPGA学习笔记——图像处理之饱和度调节(RGB)
  • MySQL 读写分离详解与 MyCat 实战部署