Rust 标准库字符串类型String及其46种常用方法

简介: String是一个可变引用,而&str是对该字符串的不可变引用,即可以更改String的数据,但是不能操作&str的数据。String 类型来自标准库,它是可修改、可变长度、可拥有所有权的同样使用UTF-8编码,且它不以空(null)值终止,实际上就是对Vec的包装,在堆内存上分配一个字符串。由&[u8]表示,UTF-8编码的字符串的引用,字符串字面值,也称作字符串切片。

Rust字符串

Rust主要有两种类型的字符串:&str和String

&str

由&[u8]表示,UTF-8编码的字符串的引用,字符串字面值,也称作字符串切片。&str用于查看字符串中的数据。它的大小是固定的,即它不能调整大小。

String

String 类型来自标准库,它是可修改、可变长度、可拥有所有权的同样使用UTF-8编码,且它不以空(null)值终止,实际上就是对Vec的包装,在堆内存上分配一个字符串。

其源代码大致如下:

pub struct String {
   
    vec: Vec<u8>,
}
impl String {
   
    pub fn new() -> String {
   
        String {
    vec: Vec::new() }
    }
    pub fn with_capacity(capacity: usize) -> String {
   
        String {
    vec: Vec::with_capacity(capacity) }
    }
    pub fn push(&mut self, ch: char) {
   
        // ...
    }
    pub fn push_str(&mut self, string: &str) {
   
        // ...
    }
    pub fn clear(&mut self) {
   
        self.vec.clear();
    }
    pub fn capacity(&self) -> usize {
   
        self.vec.capacity()
    }
    pub fn reserve(&mut self, additional: usize) {
   
        self.vec.reserve(additional);
    }
    pub fn reserve_exact(&mut self, additional: usize) {
   
        self.vec.reserve_exact(additional);
    }
    pub fn shrink_to_fit(&mut self) {
   
        self.vec.shrink_to_fit();
    }
    pub fn into_bytes(self) -> Vec<u8> {
   
        self.vec
    }
    pub fn as_str(&self) -> &str {
   
        // ...
    }
    pub fn len(&self) -> usize {
   
        // ...
    }
    pub fn is_empty(&self) -> bool {
   
        self.len() == 0
    }
    pub fn from_utf8(vec: Vec<u8>) -> Result<String, FromUtf8Error> {
   
        // ...
    }
    pub fn from_utf8_lossy<'a>(v: &'a [u8]) -> Cow<'a, str> {
   
        // ...
    }
}
impl Clone for String {
   
    fn clone(&self) -> String {
   
        String {
    vec: self.vec.clone() }
    }
    fn clone_from(&mut self, source: &Self) {
   
        self.vec.clone_from(&source.vec);
    }
}
impl fmt::Display for String {
   
    // ...
}
impl fmt::Debug for String {
   
    // ...
}
impl PartialEq for String {
   
    // ...
}
impl Eq for String {
   
    // ...
}
impl PartialOrd for String {
   
    // ...
}
impl Ord for String {
   
    // ...
}
impl Hash for String {
   
    // ...
}
impl AsRef<str> for String {
   
    // ...
}
impl AsRef<[u8]> for String {
   
    // ...
}
impl From<&str> for String {
   
    // ...
}
impl From<String> for Vec<u8> {
   
    // ...
}
// ...

String 和 &str 的区别

String是一个可变引用,而&str是对该字符串的不可变引用,即可以更改String的数据,但是不能操作&str的数据。String包含其数据的所有权,而&str没有所有权,它从另一个变量借用得来。

Rust 的标准库中还包含其他很多字符串类型,例如:OsString、OsStr、CString、CStr。

创建和输出

1、使用String::new创建空的字符串。

let empty_string = String::new();

2、使用String::from通过字符串字面量创建字符串。实际上复制了一个新的字符串。

let rust_str = "rust";
let rust_string = String::from(rust_str);

3、使用字符串字面量的to_string将字符串字面量转换为字符串。实际上复制了一个新的字符串。

let s1 = "rust_to_string";
let s2 = s1.to_string();

to_string()实际上是封装了String::from()

4、使用{}格式化输出

let s = "rust";
print!("{}",s);

索引和切片

1、String字符串是UTF-8编码,不提供索引操作。

2、Rust 使用切片来“索引”字符串,[ ] 里不是单个数字而是必须要提供范围。

范围操作符: .. 或 ..=

start..end 左开右闭区间 [start, end)

start..=end 全开区间 [start, end]

示例:

fn main() {
   
    let s = "hello, world";
    let a = &s[1..4];
    println!("{}", a);
    let a = &s[1..=4];
    println!("{}", a);
    //单个字符只能使用范围指定,不能仅用一个整数[1]
    let a = &s[1..2];
    println!("{}", a);
    let a = &s[1..=1];
    println!("{}", a);
    //等价于以下操作:
    println!("{:?}", s.chars().nth(1));
    println!("{}", s.chars().nth(1).unwrap());
}

输出:

ell
ello
e
e
Some('e')
e

拼接和迭代

1、拼接直接使用加号 +

fn main() {
   
    let s1 = String::from("hello");
    let s2 = String::from("world");

    let s = s1 + ", " + &s2 ;

    println!("{}", s);
}

输出:

hello, world

2、各种遍历(迭代)

.chars()方法:该方法返回一个迭代器,可以遍历字符串的Unicode字符。

let s = String::from("Hello, Rust!");
for c in s.chars() {
println!("{}", c);
}
.bytes()方法:该方法返回一个迭代器,可以遍历字符串的字节序列。

let s = String::from("Hello, Rust!");
for b in s.bytes() {
println!("{}", b);
}
.chars().enumerate()方法:该方法返回一个元组迭代器,可以同时遍历字符和它们在字符串中的索引。

let s = String::from("Hello, Rust!");
for (i, c) in s.chars().enumerate() {
println!("{}: {}", i, c);
}
.split()方法:该方法返回一个分割迭代器,可以根据指定的分隔符将字符串分割成多个子字符串,然后遍历每个子字符串。

let s = String::from("apple,banana,orange");
for word in s.split(",") {
println!("{}", word);
}
.split_whitespace()方法:该方法返回一个分割迭代器,可以根据空格将字符串分割成多个子字符串,然后遍历每个子字符串。

let s = String::from("The quick brown fox");
for word in s.split_whitespace() {
println!("{}", word);
}

3. 使用切片循环输出

fn main() {
   
    let s = String::from("The quick brown fox"); 
    let mut i = 0;
    while i < s.len() {
   
        print!("{}", &s[i..=i]);
        i += 1;
    }
    println!();
    while i > 0 {
   
        i -= 1;
        print!("{}", &s[i..=i]);

    }
    println!();
    loop {
   
        if i >= s.len() {
   
            break;
        }
        print!("{}", &s[i..i+1]);
        i += 1;
    }
    println!();
}

输出:

The quick brown fox
xof nworb kciuq ehT
The quick brown fox

String除了以上这几种最基本的操作外,标准库提供了删增改等等各种各样的方法以方便程序员用来操作字符串。以下归纳了String字符串比较常用的46种方法:

String 方法

1、 new
new():创建一个空的 String 对象。

let s = String::new();

2、 from
from():从一个字符串字面量、一个字节数组或另一个字符串对象中创建一个新的 String 对象。

let s1 = String::from("hello");
let s2 = String::from_utf8(vec![104, 101, 108, 108, 111]).unwrap();
let s3 = String::from(s1);

3、 with_capacity
with_capacity():创建一个具有指定容量的 String 对象。

let mut s = String::with_capacity(10);
s.push('a');

4、 capacity
capacity():返回字符串的容量(以字节为单位)。

let s = String::with_capacity(10);
assert_eq!(s.capacity(), 10);

5、 reserve
reserve():为字符串预留更多的空间。

let mut s = String::with_capacity(10);
s.reserve(10);

6、 shrink_to_fit
shrink_to_fit():将字符串的容量缩小到它所包含的内容所需的最小值。

let mut s = String::from("foo");
s.reserve(100);
assert!(s.capacity() >= 100);
s.shrink_to_fit();
assert_eq!(3, s.capacity());

7、 shrink_to
shrink_to():将字符串的容量缩小到指定下限。如果当前容量小于下限,则这是一个空操作。

let mut s = String::from("foo");
s.reserve(100);
assert!(s.capacity() >= 100);
s.shrink_to(10);
assert!(s.capacity() >= 10);
s.shrink_to(0);
assert!(s.capacity() >= 3);

8、 push
push():将一个字符追加到字符串的末尾。

let mut s = String::from("hello");
s.push('!');

9、 push_str
push_str():将一个字符串追加到字符串的末尾。

let mut s = String::from("hello");
s.push_str(", world!");

10、 pop
pop():将字符串的最后一个字符弹出,并返回它。

let mut s = String::from("hello");
let last = s.pop();

11、 truncate
truncate():将字符串截短到指定长度,此方法对字符串的分配容量没有影响。

let mut s = String::from("hello");
s.truncate(2);
assert_eq!("he", s);
assert_eq!(2, s.len());
assert_eq!(5, s.capacity());

12、 clear
clear():将字符串清空,此方法对字符串的分配容量没有影响。

let mut s = String::from("foo");
s.clear();
assert!(s.is_empty());
assert_eq!(0, s.len());
assert_eq!(3, s.capacity());

13、 remove
remove():从字符串的指定位置移除一个字符,并返回它。

let mut s = String::from("hello");
let second = s.remove(1);

14、 remove_range
remove_range():从字符串的指定范围删除所有字符。

let mut s = String::from("hello");
s.remove_range(1..3);

15、 insert
insert():在字符串的指定位置插入一个字符。

let mut s = String::from("hello");
s.insert(2, 'l');

16、 insert_str
insert_str():在字符串的指定位置插入一个字符串。

let mut s = String::from("hello");
s.insert_str(2, "ll");

17、 replace
replace():将字符串中的所有匹配项替换为另一个字符串。

let mut s = String::from("hello, world");
let new_s = s.replace("world", "Rust");

18、 replace_range
replace_range():替换字符串的指定范围内的所有字符为另一个字符串。

let mut s = String::from("hello");
s.replace_range(1..3, "a");

19、 split
split():将字符串分割为一个迭代器,每个元素都是一个子字符串。

let s = String::from("hello, world");
let mut iter = s.split(", ");
assert_eq!(iter.next(), Some("hello"));
assert_eq!(iter.next(), Some("world"));
assert_eq!(iter.next(), None);

20、 split_whitespace
split_whitespace():将字符串分割为一个迭代器,每个元素都是一个不包含空格的子字符串。

let s = String::from("   hello   world   ");
let mut iter = s.split_whitespace();
assert_eq!(iter.next(), Some("hello"));
assert_eq!(iter.next(), Some("world"));
assert_eq!(iter.next(), None);

21、 split_at
split_at():将字符串分成两个部分,在指定的位置进行分割。

let s = String::from("hello");
let (left, right) = s.split_at(2);

22、 split_off
split_off():从字符串的指定位置分离出一个子字符串,并返回新的 String 对象。

let mut s = String::from("hello");
let new_s = s.split_off(2);

23、 len
len():返回字符串的长度(以字节为单位)。

let s = String::from("hello");
assert_eq!(s.len(), 5);

24、 is_empty
is_empty():检查字符串是否为空。

let s = String::from("");
assert!(s.is_empty());

25、 as_bytes
as_bytes():将 String 对象转换为字节数组。

let s = String::from("hello");
let bytes = s.as_bytes();

26、 into_bytes
into_bytes():将 String 对象转换为字节向量。

let s = String::from("hello");
let bytes = s.into_bytes();
assert_eq!(&[104, 101, 108, 108, 111][..], &bytes[..]);

27、 clone
clone():创建一个与原始字符串相同的新字符串。

let s1 = String::from("hello");
let s2 = s1.clone();

28、 eq
eq():比较两个字符串是否相等。

let s1 = String::from("hello");
let s2 = String::from("hello");
assert!(s1.eq(&s2));

29、 contains
contains():检查字符串是否包含指定的子字符串。

let s = String::from("hello");
assert!(s.contains("ell"));

30、 starts_with
starts_with():检查字符串是否以指定的前缀开头。

let s = String::from("hello");
assert!(s.starts_with("he"));

31、 ends_with
ends_with():检查字符串是否以指定的后缀结尾。

let s = String::from("hello");
assert!(s.ends_with("lo"));

32、 find
find():查找字符串中第一个匹配指定子字符串的位置。

let s = String::from("hello");
let pos = s.find("l");
assert_eq!(pos, Some(2));

33、 rfind
rfind():查找字符串中最后一个匹配指定子字符串的位置。

let s = String::from("hello");
let pos = s.rfind("l");
assert_eq!(pos, Some(3));

34、 trim
trim():删除字符串两端的所有空格。

let s = String::from("   hello   ");
let trimmed = s.trim();

35、 trim_start
trim_start():删除字符串开头的所有空格。

let s = String::from("   hello   ");
let trimmed = s.trim_start();

36、 trim_end
trim_end():删除字符串末尾的所有空格。

let s = String::from("   hello   ");
let trimmed = s.trim_end();

37、 to_lowercase
to_lowercase():将字符串中的所有字符转换为小写。

let s = String::from("HeLLo");
let lower = s.to_lowercase();

38、 to_uppercase
to_uppercase():将字符串中的所有字符转换为大写。

let s = String::from("HeLLo");
let upper = s.to_uppercase();

39、 retain
retain():保留满足指定条件的所有字符。

let mut s = String::from("hello");
s.retain(|c| c != 'l');

40、 drain
drain():从字符串中删除指定范围内的所有字符,并返回它们的迭代器。

let mut s = String::from("hello");
let mut iter = s.drain(1..3);
assert_eq!(iter.next(), Some('e'));
assert_eq!(iter.next(), Some('l'));
assert_eq!(iter.next(), None);

41、 lines
lines():将字符串分割为一个迭代器,每个元素都是一行文本。

let s = String::from("hello\nworld");
let mut iter = s.lines();
assert_eq!(iter.next(), Some("hello"));
assert_eq!(iter.next(), Some("world"));
assert_eq!(iter.next(), None);

42、 chars
chars():将字符串分割为一个迭代器,每个元素都是一个字符。

let s = String::from("hello");
let mut iter = s.chars();
assert_eq!(iter.next(), Some('h'));
assert_eq!(iter.next(), Some('e'));
assert_eq!(iter.next(), Some('l'));
assert_eq!(iter.next(), Some('l'));
assert_eq!(iter.next(), Some('o'));
assert_eq!(iter.next(), None);

43、 bytes
bytes():将字符串分割为一个迭代器,每个元素都是一个字节。

let s = String::from("hello");
let mut iter = s.bytes();
assert_eq!(iter.next(), Some(104));
assert_eq!(iter.next(), Some(101));
assert_eq!(iter.next(), Some(108));
assert_eq!(iter.next(), Some(108));
assert_eq!(iter.next(), Some(111));
assert_eq!(iter.next(), None);

44、 as_str
as_str():将 String 对象转换为字符串切片。

let s = String::from("hello");
let slice = s.as_str();

45、 as_mut_str
as_mut_str():将 String 对象转换为可变字符串切片。

let mut s = String::from("foobar");
let s_mut_str = s.as_mut_str();
s_mut_str.make_ascii_uppercase();
assert_eq!("FOOBAR", s_mut_str);

46、 remove_matches
remove_matches():删除字符串中所有匹配的子串。

#![feature(string_remove_matches)]  //使用不稳定的库功能,此行必须
let mut s = String::from("Trees are not green, the sky is not blue.");
s.remove_matches("not ");
assert_eq!("Trees are green, the sky is blue.", s);

String字符串包括但不限于此46种方法,更多方法请见官方文档:

String in std::string - Rust

目录
相关文章
|
3月前
|
安全 Java API
【Java字符串操作秘籍】StringBuffer与StringBuilder的终极对决!
【8月更文挑战第25天】在Java中处理字符串时,经常需要修改字符串,但由于`String`对象的不可变性,频繁修改会导致内存浪费和性能下降。为此,Java提供了`StringBuffer`和`StringBuilder`两个类来操作可变字符串序列。`StringBuffer`是线程安全的,适用于多线程环境,但性能略低;`StringBuilder`非线程安全,但在单线程环境中性能更优。两者基本用法相似,通过`append`等方法构建和修改字符串。
64 1
|
5天前
|
索引 Python
String(字符串)
String(字符串)。
12 3
|
27天前
|
NoSQL Redis
Redis 字符串(String)
10月更文挑战第16天
37 4
|
1月前
|
数据可视化 Java
让星星月亮告诉你,通过反射创建类的实例对象,并通过Unsafe theUnsafe来修改实例对象的私有的String类型的成员属性的值
本文介绍了如何使用 Unsafe 类通过反射机制修改对象的私有属性值。主要包括: 1. 获取 Unsafe 的 theUnsafe 属性:通过反射获取 Unsafe类的私有静态属性theUnsafe,并放开其访问权限,以便后续操作 2. 利用反射创建 User 类的实例对象:通过反射创建User类的实例对象,并定义预期值 3. 利用反射获取实例对象的name属性并修改:通过反射获取 User类实例对象的私有属性name,使用 Unsafe`的compareAndSwapObject方法直接在内存地址上修改属性值 核心代码展示了详细的步骤和逻辑,确保了对私有属性的修改不受 JVM 访问权限的限制
50 4
|
1月前
|
canal 安全 索引
(StringBuffer和StringBuilder)以及回文串,字符串经典习题
(StringBuffer和StringBuilder)以及回文串,字符串经典习题
33 5
|
1月前
|
存储 分布式计算 NoSQL
大数据-40 Redis 类型集合 string list set sorted hash 指令列表 执行结果 附截图
大数据-40 Redis 类型集合 string list set sorted hash 指令列表 执行结果 附截图
26 3
|
1月前
|
存储 JavaScript 前端开发
JavaScript 字符串(String) 对象
JavaScript 字符串(String) 对象
43 3
|
1月前
|
Rust API
【Rust学习】09_方法语法
结构体让你可以创建出在你的领域中有意义的自定义类型。通过结构体,我们可以将相关联的数据片段联系起来并命名它们,这样可以使得代码更加清晰。在 impl 块中,你可以定义与你的类型相关联的函数,而方法是一种相关联的函数,允许您指定结构体的实例具有的行为。 但是结构体并不是创建自定义类型的唯一方式:让我们转向 Rust 的 enum 功能,将另一个工具添加到你的工具箱中。
14 0
|
2月前
|
设计模式 Rust 安全
30天拿下Rust之高级类型
30天拿下Rust之高级类型
23 0
|
2月前
|
存储 C++
C++(五)String 字符串类
本文档详细介绍了C++中的`string`类,包括定义、初始化、字符串比较及数值与字符串之间的转换方法。`string`类简化了字符串处理,提供了丰富的功能如字符串查找、比较、拼接和替换等。文档通过示例代码展示了如何使用这些功能,并介绍了如何将数值转换为字符串以及反之亦然的方法。此外,还展示了如何使用`string`数组存储和遍历多个字符串。