【RUST学习日记】第15课 字符串的常用方法(一)

简介: 【RUST学习日记】第15课 字符串的常用方法(一)

0x00 回顾与开篇


前面用了两篇文章介绍了Rust的字符串,也了解了它们之间的联系和区别。这节课开始介绍Rust字符串的修改,添加,删除等常用的方法,进一步的来了解Rust字符串。


0x01 追加(Push)


在字符串尾部可以使用push()方法追加单个字符char,也可以使用push_str()方法追加字符串字面量。这两个方法都是在原有的字符串上追加,并不会返回新的字符串。由于字符串追加操作要修改原来的字符串,则该字符串必须是可变的。即字符串变量必须由mut关键字修饰


示例代码如下:

let mut string = String::from("hello ");
    string.push('r');
    println!("追加字符 push() -> {}", string);
    string.push_str("ust!");
    println!("追加字符串 push_str() -> {}", string);

代码运行结果:

追加字符 push() -> hello r
追加字符串 push_str() -> hello rust!


0x02 插入(Insert)


可以使用insert()方法插入单个字符char,也可以使用insert_str()方法插入字符串字面量。与push()方法不同,这俩方法需要传入两个参数,第一个参数是字符(串)插入位置的索引,第二个参数是要插入的字符(串)。索引从0开始计数,如果越界则会发生错误。由于字符串插入操作要修改原来的字符串,则该字符串必须是可变的。即字符串变量必须由mut关键字修饰


示例代码如下:

let mut insert_string = String::from("hello rust!");
    insert_string.insert(5, ',');
    println!("插入字符 insert() -> {}", insert_string);
    insert_string.insert_str(6, " I like");
    println!("插入字符串 insert_str() -> {}", insert_string);

代码运行结果:

插入字符 insert() -> hello, rust!
插入字符串 insert_str() -> hello, I like rust!


0x03 连接(Catenate)


1、使用+或者+=连接字符串


使用+或者+=连接字符串,要求右边的参数必须为字符串的切片引用(Slice)类型。其实当调用+的操作符时,相当于调用了string标准库中的add方法。


源码如下:

#[inline]

fn add(mut self, other: &str) -> String {
   self.push_str(other);
   self
}

这里add方法的第二个参数是一个引用的类型。因此我们在使用+,必须传递切片引用类型。不能直接传递String类型。++=都是返回一个新的字符串。所以变量声明可以不需要mut关键字修饰。

示例代码如下:

let string_append = String::from("hello ");
    let string_rust = String::from("rust");
    // &string_rust会自动解引用为&str
    let result = string_append + &string_rust;
    let mut result = result + "!";
    result += "!!!";
    println!("连接字符串 + -> {}", result);

代码运行结果:

连接字符串 + -> hello rust!!!!

看到这里,是不是有人有问题要问。

Q:看源码明明是操作了原有的字符串啊,只是在原有的字符串中调用了push_str追加了新的内容,为啥还要返回一个新的字符串呢?岂不是多此一举吗?

A:那我们就直接输出下string_append这个字符串看下不就可以了吗。如果你打印string_append,你会很绝望,因为编译器会发生下面的错误。

println!("输出 string_append -> {}", string_append);
|                                 ^^^^^^^^^^^^^ value borrowed here after move

直译的意思是:这个值在移动后又被使用了。简单解释下,string_append这个变量通过调用了add方法后,所有权被转移到add方法里面,add方法调用后就被释放了,同时string_append也被释放了。再使用string_append就会发生错误。仅了解即可,这里涉及到所有权转移(Move)的相关知识。仅仅了解即可,我在这里埋个坑,后面将所有权会详细解释。

2、使用format!连接字符串

format!这种方式适用于String&strformat!的用法与print!的用法类似,在前面“第9课——输入与输出”已经详细介绍过了。

示例代码如下:

let s1 = "hello";
    let s2 = String::from("rust");
    let s = format!("{} {}!", s1, s2);
    println!("{}", s);

代码运行结果:

hello rust!


0x04 替换(Replace)


如果想要把字符串中的某个字符串替换成其它的字符串,那可以使用replace()方法。与替换有关的方法有三个。


1、replace


该方法可适用于String和&str类型。replace方法接收两个参数,第一个参数是要被替换的字符串,第二个参数是新的字符串。该方法会替换所有匹配到的字符串。该方法是返回一个新的字符串,而不是操作原来的字符串。

示例代码如下:

// replacen
    let string_replace = "I like rust. Learning rust is my favorite!";
    let new_string_replace = string_replace.replace("rust", "RUST");
    dbg!(new_string_replace);

代码运行结果:

new_string_replace = "I like RUST. Learning RUST is my favorite!"


2、replacen


该方法可适用于String和&str类型。replacen方法接收三个参数,前两个参数与replace方法一样,第三个参数则表示替换的个数。该方法是返回一个新的字符串,而不是操作原来的字符串。

示例代码如下:

// replacen
    let string_replacen = "I like rust. Learning rust is my favorite!";
    let new_string_replacen = string_replacen.replacen("rust", "RUST", 1);
    dbg!(new_string_replacen);

代码运行结果:

new_string_replacen = "I like RUST. Learning rust is my favorite!"


3、replace_range


该方法仅适用于String类型。replace_range接收两个参数,第一个参数是要替换字符串的范围(Range),第二个参数是新的字符串。该方法是直接操作原来的字符串,不会返回新的字符串。该方法需要使用mut关键字修饰。

let mut string_replace_range = String::from("I like rust!");
    string_replace_range.replace_range(7..8, "R");
    dbg!(string_replace_range);

代码运行结果:

string_replace_range = "I like Rust!"


0x05 删除(Delete)


与字符串删除相关的方法有4个,他们分别是popremovetruncateclear这四个方法仅适用于String类型。


1、pop——删除并返回字符串的最后一个字符。


该方法是直接操作原来的字符串。但是存在返回值,其返回值是一个Option<char>类型,如果字符串为空,则返回None。有关Option类型后续章节将会介绍。

示例代码如下:

let mut string_pop = String::from("rust pop 中文!");
    let p1 = string_pop.pop();
    let p2 = string_pop.pop();
    dbg!(p1);
    dbg!(p2);
    dbg!(string_pop);

代码运行结果:

p1 = Some(
    '!',
)
p2 = Some(
    '文',
)
string_pop = "rust pop 中"


2、remove——删除并返回字符串中指定位置的字符


该方法是直接操作原来的字符串。但是存在返回值,其返回值是删除位置的字符串只接收一个参数,表示该字符起始索引位置。remove方法是按照字节来处理字符串的,如果参数所给的位置不是合法的字符边界,则会发生错误。


什么是不合法的字符边界?

在Rust中,一个英文字符或者阿拉伯数字是占一个字节的,而一个汉字是占3个字符串。可以使用std::mem::size_of_val()方法查看在内存占用几个字节。还有一些Emoji表情还占了4个字节。

也许你会问为什么会这样呢?这个与UTF-8编码有关系,这里就不解释了,如果后面有时间,我可以拿出一篇文章来讲解下Unicode的背景。如果想知道答案也可以通过网络搜索下。

示例代码如下:

let word = "中";
    let ch = "1";
    println!("word 占 {} 个字节", std::mem::size_of_val(word));
    println!("ch 占 {} 个字节", std::mem::size_of_val(ch));

代码运行结果:

word 占 3 个字节
ch 占 1 个字节

经过上面的例子,也许你理解了什么叫做不合法的字符边界。看下面的代码示例,string_remove是一个String类型,按照上面说的规则,计算下的它的字节长度是18字节。如果要删除第一个汉字,那就传参数为0。如果想直接删除第二个汉字,则需要传参数为3。如果你传递参数为1或者2,则会出现不合法的字符边界错误。

示例代码如下:

let mut string_remove = String::from("测试remove方法");
println!("string_remove 占 {} 个字节", std::mem::size_of_val(string_remove.as_str()));
// 删除第一个汉字
string_remove.remove(0);
// 下面代码会发生错误
// string_remove.remove(1);
// 直接删除第二个汉字
// string_remove.remove(3);
dbg!(string_remove);
代码运行结果:
string_remove 占 18 个字节
string_remove = "试rmove方法"


3、truncate——删除字符串中从指定位置开始到结尾的全部字符。


该方法是直接操作原来的字符串。无返回值。该方法truncate方法是按照字节来处理字符串的,如果参数所给的位置不是合法的字符边界,则会发生错误。


示例代码如下:

let mut string_truncate = String::from("测试truncate");
string_truncate.truncate(3);
dbg!(string_truncate);

代码运行结果:

string_truncate = "测"


4、clear——清空字符串


该方法是直接操作原来的字符串。调用后,删除字符串中的所有字符,相当于truncate方法参数为0的时候。


示例代码如下:

let mut string_clear = String::from("string clear");
string_clear.clear();
dbg!(string_clear);

代码运行结果:

string_clear = ""


0x06 小结


简单介绍了字符串的常用修改方法,总共分为追加,插入,连接,替换,删除5部分。下节继续介绍字符串的常用方法——字符串的访问。

相关文章
|
4天前
|
Rust 算法 安全
学习Rust
【10月更文挑战第13天】学习Rust
28 8
|
5天前
|
Rust 安全 算法
Rust的学习
【10月更文挑战第12天】Rust的学习
13 2
|
5天前
|
Rust 算法 安全
如何学习Rust编程?
【10月更文挑战第12天】如何学习Rust编程?
17 1
|
17天前
|
Rust API
【Rust学习】09_方法语法
结构体让你可以创建出在你的领域中有意义的自定义类型。通过结构体,我们可以将相关联的数据片段联系起来并命名它们,这样可以使得代码更加清晰。在 impl 块中,你可以定义与你的类型相关联的函数,而方法是一种相关联的函数,允许您指定结构体的实例具有的行为。 但是结构体并不是创建自定义类型的唯一方式:让我们转向 Rust 的 enum 功能,将另一个工具添加到你的工具箱中。
10 0
|
1月前
|
Rust 索引
【Rust学习】08_使用结构体代码示例
为了了解我们何时可能想要使用结构体,让我们编写一个计算长方形面积的程序。我们将从使用单个变量开始,然后重构程序,直到我们改用结构体。
72 2
|
1月前
|
存储 Rust 编译器
【Rust学习】07_结构体说明
**struct**或 ***structure***是一种自定义数据类型,允许您命名和包装多个相关的值,从而形成一个有意义的组合。如果您熟悉面向对象的语言,那么**struct**就像对象中的数据属性。在本章中,我们将比较和对比元组与结构体,在您已经知道的基础上,来演示结构体是对数据进行分组的更好方法。
21 1
|
2月前
|
Rust 安全 Go
揭秘Rust语言:为何它能让你在编程江湖中,既安全驰骋又高效超车,颠覆你的编程世界观!
【8月更文挑战第31天】Rust 是一门新兴的系统级编程语言,以其卓越的安全性、高性能和强大的并发能力著称。它通过独特的所有权和借用检查机制解决了内存安全问题,使开发者既能享受 C/C++ 的性能,又能避免常见的内存错误。Rust 支持零成本抽象,确保高级抽象不牺牲性能,同时提供模块化和并发编程支持,适用于系统应用、嵌入式设备及网络服务等多种场景。从简单的 “Hello World” 程序到复杂的系统开发,Rust 正逐渐成为现代软件开发的热门选择。
56 1
|
9天前
|
Rust 安全 网络安全
在 Rust 语言中,寻找企业上网行为管理软件的突破
在数字化企业环境中,上网行为管理软件对于保障网络安全和提升工作效率至关重要。Rust 语言凭借其安全性、高性能和并发性,为开发此类软件提供了新机遇。本文通过几个 Rust 代码示例,展示了如何实现网址检查、访问频率统计及访问控制等功能,旨在探索 Rust 在企业上网行为管理中的应用潜力。
19 0
|
2月前
|
Rust 安全 编译器
初探 Rust 语言与环境搭建
Rust 是一门始于2006年的系统编程语言,由Mozilla研究员Graydon Hoare发起,旨在确保内存安全而不牺牲性能。通过所有权、借用和生命周期机制,Rust避免了空指针和数据竞争等问题,简化了并发编程。相较于C/C++,Rust在编译时预防内存错误,提供类似C++的语法和更高的安全性。Rust适用于系统编程、WebAssembly、嵌入式系统和工具开发等领域。其生态系统包括Cargo包管理器和活跃社区。学习资源如&quot;The Book&quot;和&quot;Rust by Example&quot;帮助新手入门。安装Rust可通过Rustup进行,支持跨平台操作。
138 2
初探 Rust 语言与环境搭建
|
2月前
|
Rust 安全 程序员
Rust 语言的防错机制太惊人了!安全编码从此不再是难题,快来一探究竟!
【8月更文挑战第31天】《安全编码原则:Rust 语言中的防错机制》探讨了代码安全的重要性,并详细介绍了Rust语言如何通过内存安全模型、所有权与借用规则等特性,在编译阶段检测并阻止潜在错误,如缓冲区溢出和悬空指针。文章还讨论了类型安全、边界检查等其他安全特性,并提出了遵循不可变引用、避免裸指针及充分测试等实用编码原则,以进一步提升代码质量和安全性。随着Rust在软件开发中的应用日益广泛,掌握其安全编码原则变得尤为重要。
50 0