趣味学RUST基础篇(String)

String:Rust 里的"魔法卷轴"!

在前面的内容,我们学会了用 Vec<T> 装整数、装枚举,像个收纳高手。

但作为冒险者,你总得写点日记吧?比如:

"今日击败恶龙,获得金币 ×100,太棒了"

这就需要一个能装文字 的容器------在 Rust 里,它就是 String

但别被名字骗了,String 可不是简单的"一串字符"。它是个会魔法的卷轴,能装中文、阿拉伯文、俄文、emoji......\但正因为太强大,它也比你想象的复杂得多。接下来,我们揭开它的神秘面纱!

首先:什么是"字符串"?

在 Rust 世界里,有两种"文字":

类型 名字 特点
&str 字符串切片 "只读卷轴",通常来自字面量,比如 "hello"
String 动态字符串 "可编辑卷轴",能增、删、改,像 Vec<T> 一样灵活

通常我们说"字符串",就是指这两个一起。

其他语言可能把它们混为一谈,但 Rust 很认真:"只读"和"可变"是两回事!

创建一个"魔法卷轴"

方法一:空卷轴启动!

rust 复制代码
let mut s = String::new();

就像买了一张空白羊皮纸,等着你写点什么。


方法二:从文字变卷轴!

rust 复制代码
let data = "初始内容";
let s = data.to_string();  // 变!

或者更直接:

rust 复制代码
let s = "初始内容".to_string();
let s = String::from("初始内容");  // 效果一样!

to_string() 还是 String::from()

随你喜欢!就像"番茄炒蛋"和"蛋炒番茄",看你心情!


它支持所有语言!

StringUTF-8 编码的,所以你可以写:

rust 复制代码
let 你好 = String::from("你好");
let привет = String::from("Здравствуйте");
let 안녕 = String::from("안녕하세요");
let 😎 = String::from("今天真棒!");

统统支持!

更新字符串:往卷轴上写字!

1. 用 push_str 添加文字

rust 复制代码
let mut s = String::from("Hello");
s.push_str(", world!");

现在 s"Hello, world!"

有趣的是:push_str 接收的是 &str(字符串切片),所以它不拿走所有权

rust 复制代码
let mut s1 = String::from("foo");
let s2 = "bar";
s1.push_str(s2);
println!("s2 还能用:{s2}");  // 正常打印!

Rust 很贴心,不会偷偷把你的字符串"吃掉"。


2. 用 push 添加单个字符

rust 复制代码
let mut s = String::from("lo");
s.push('l');  // 注意是单引号!

结果:"lol"

# 拼接字符串:把多个卷轴合成一个!

方法一:用 +

rust 复制代码
let s1 = String::from("Hello, ");
let s2 = String::from("world!");
let s3 = s1 + &s2;  // 注意:&s2 是引用

结果是 "Hello, world!"

但注意:s1 被"吃掉"了!

你不能再用 s1,因为它已经被移动到 s3 里了。

原理:+ 其实调用了 add(self, &str),它拿走了 self 的所有权。

所以这行代码其实是:

  • 拿走 s1
  • s2 的内容复制进来
  • 返回一个全新的 String

虽然写起来像拼积木,但背后是"拆了旧的,建个新的"。


方法二:用 format! 宏 ------ 推荐!

如果你要拼接多个字符串,+ 就太难看了:

rust 复制代码
let s = s1 + "-" + &s2 + "-" + &s3;  // 眼都花了!

这时,用 format! 宏,优雅又安全:

rust 复制代码
let s = format!("{}-{}-{}", s1, s2, s3);

不获取所有权、 代码清晰、 性能好, 就像 println!,但不打印,而是返回一个 String


不能用索引?s[0] 为什么不行?

在 Python、JavaScript 里,你可能习惯这么写:

python 复制代码
s = "hello"
print(s[0])  # 'h'

但在 Rust,这样写会编译失败

rust 复制代码
let s = String::from("hello");
let h = s[0];  // 编译错误!

为什么?因为 String 在 Rust 里不是"字符数组"那么简单!

🔍 深入魔法:String 到底怎么存的?

String 本质是 Vec<u8> ------ 一串字节

比如:

rust 复制代码
let hello = String::from("Hola");

它在内存里是:[72, 111, 108, 97] ------ 4 个字节。

但如果是:

rust 复制代码
let hello = String::from("Здравствуйте");

这 12 个西里尔字母,却占了 24 个字节!因为每个字母用 2 字节 UTF-8 编码。

所以,如果你写:

rust 复制代码
let s = &hello[0..1];  // 只取第一个字节?

你会得到一个不完整的字节序列,根本不是合法字符!

Rust 宁愿让你编译失败,也不让你写出"看似正确实则乱码"的代码。


三种看字符串的方式

Rust 让你明确选择:你想怎么"读"字符串?

方式 方法 例子("नमस्ते")
字节 .bytes() 18 个字节 [224, 164, ...]
字符(Unicode 标量值) .chars() 6 个 char'न', 'म', 'स', '्', 'त', 'े'
字形簇(视觉上的"字") 需要外部库 4 个:"न", "म", "स्", "ते"

.chars() 最常用,但注意:像 这种是"变音符号",单独没意义。


遍历字符串:推荐方式

遍历每个字符:

rust 复制代码
for c in "नमस्ते".chars() {
    println!("{c}");
}

遍历每个字节:

rust 复制代码
for b in "नमस्ते".bytes() {
    println!("{b}");
}

想要"字形簇"?标准库没给,但你可以在 crates.iounicode-segmentation 这样的库。

为什么 Rust 要这么复杂?

因为:

"简单"往往藏着陷阱。

其他语言让你用 s[0],但遇到中文、emoji 时,可能返回乱码或半个字符。

Rust 说:

"我宁可你现在觉得麻烦,也别将来在生产环境炸了服务器。"

所以它强制你思考:

  • 我要的是字节?字符?还是视觉上的"字"?
  • 我的代码是否真正理解 UTF-8?

#String 使用口诀

操作 推荐方式
创建 String::from("...")"...".to_string()
拼接 format!("{} {}", s1, s2)(安全又清晰)
添加 push_str()(加字符串)、push()(加字符)
遍历 .chars()(最常用)或 .bytes()
切片 &s[0..4](必须按字节,小心越界!)
索引 不支持!用 .chars().nth(0) 代替(但性能差)

总结:

字符串,远比你想象的复杂。

Rust 没有隐藏这种复杂性,而是把它摆在你面前,让你写出真正健壮的代码。

相关推荐
hrrrrb28 分钟前
【Python】文件处理(二)
开发语言·python
先知后行。1 小时前
QT实现计算器
开发语言·qt
掘根1 小时前
【Qt】常用控件3——显示类控件
开发语言·数据库·qt
catchadmin1 小时前
PHP 快速集成 ChatGPT 用 AI 让你的应用更聪明
人工智能·后端·chatgpt·php
西阳未落5 小时前
C++基础(21)——内存管理
开发语言·c++·面试
我的xiaodoujiao5 小时前
Windows系统Web UI自动化测试学习系列2--环境搭建--Python-PyCharm-Selenium
开发语言·python·测试工具
callJJ5 小时前
从 0 开始理解 Spring 的核心思想 —— IoC 和 DI(2)
java·开发语言·后端·spring·ioc·di
hsjkdhs7 小时前
万字详解C++之构造函数析构函数
开发语言·c++
你的人类朋友7 小时前
JWT的组成
后端
Lin_Aries_04218 小时前
容器化简单的 Java 应用程序
java·linux·运维·开发语言·docker·容器·rpc