30天拿下Rust之切片

概述

在Rust中,切片是一种非常重要的引用类型。它允许你安全地引用一段连续内存中的数据,而不需要拥有这些数据的所有权。切片不包含分配的内存空间,它仅仅是一个指向数据开始位置和长度的数据结构。切片是对数组的一个连续引用,它提供了一种方便、高效的方式来操作数组的一部分。切片本身并不拥有数据,它只是原始数组的一个视图,因此创建切片通常是一个低开销的操作。

切片的声明

在Rust中,切片的声明格式如下。

ini 复制代码
let slice_name: [T; n] = &array[start..end];

下面,我们详细介绍切片声明中的各个元素。

slice_name:切片变量取的名字。

T; n\]:是一个泛型,表示一个包含n个类型为T的元素的切片。但在实际声明中,通常不需要指定n,因为Rust会根据初始化的数据自动推断出长度。 \&array\[start..end\]:创建一个从array中的start索引到end索引(但不包含 end 索引)的切片。start和end是范围操作符..的参数,用于定义切片的开始位置和结束位置(但不包括结束位置)。注意:start索引可以不写,不写时默认为0;end索引也可以不写,不写时默认为array的最后一个元素的索引。 在下面的示例代码中,我们使用数组的切片操作创建了slice切片,Rust会自动推断出slice切片的类型为:\&\[i32\]。 ```ini fn main() { let array = [1, 2, 3, 4, 5]; // 创建一个从索引1到索引4(不包含4)的切片 let slice = &array[1..4]; assert_eq!(slice, &[2, 3, 4]); } ``` 如果我们要声明一个可变切片,可以使用mut关键字。在下面的示例代码中,\&mut表示对原始数组的一个可变引用,这意味着你可以通过这个切片修改原始数组的内容。 ```ini fn main() { let mut array = [1, 2, 3, 4, 5]; // 可变切片 let mutable_slice = &mut array[1..4]; // 输出:[2, 3, 4] println!("{:?}", mutable_slice); } ``` 如果我们要声明一个空的切片,可以使用空数组字面量来初始化。在下面的示例代码中,empty_slice是一个空的i32类型切片。注意:我们在这里显式指定了切片的类型,因为空切片本身不包含足够的信息来自动推断类型。 ```rust fn main() { let empty_slice: &[i32] = &[]; // 输出:[] println!("{:?}", empty_slice); } ``` ### 切片的使用 1、获取切片的长度,可以使用len()方法。 ```ini fn main() { let text = "Hello, CSDN"; let word = &text[0..5]; let len: usize = word.len(); // 输出: 5 println!("{}", len); } ``` 2、切片可以通过索引来访问其内部元素。切片的索引遵循与数组相同的规则:从0开始,并且是基于半开区间\[start, end)的原则,即:包含起始索引,但不包含结束索引。 ```ini fn main() { let numbers = [1, 2, 3, 4, 5]; let slice: &[i32] = &numbers[2..]; // 输出:3 println!("{}", slice[0]); let mut mut_numbers = [1, 2, 3, 4, 5]; let mut_slice: &mut [i32] = &mut mut_numbers[1..]; // 修改切片中的元素 mut_slice[0] *= 10; // 原始数组会被修改,输出:20 println!("{}", mut_numbers[1]); } ``` 注意:索引操作不会进行越界检查,如果尝试访问超出切片范围的索引,将导致运行时错误。为了安全地访问切片元素,可以使用get()方法。 ```csharp fn main() { let numbers = [1, 2, 3, 4, 5]; let slice: &[i32] = &numbers[2..]; // 安全访问切片元素 if let Some(value) = slice.get(1) { // 输出:element is: 4 println!("element is: {}", value); } else { println!("out of bounds"); } } ``` 3、切片可以通过迭代器来进行遍历。我们可以使用for循环配合.iter()方法来迭代不可变切片中的元素,或者使用.iter_mut()方法来迭代可变切片中的元素。 ```typescript fn main() { let numbers = [1, 2, 3, 4, 5]; let slice: &[i32] = &numbers[2..]; // 输出:3 4 5 for number in slice.iter() { println!("{}", number); } let mut mut_numbers = [1, 2, 3, 4, 5]; let mut_slice: &mut [i32] = &mut mut_numbers[..]; // 修改切片中的元素 for number in mut_slice.iter_mut() { *number *= 10; } // 输出:[10, 20, 30, 40, 50] println!("{:?}", mut_numbers); } ``` 4、字符串切片(\&str)可以通过chars()方法来迭代其中的Unicode字符。这是因为:Rust中的字符串是UTF-8编码的,而一个Unicode字符可能由1到4个字节组成。chars()方法会返回一个实现了Iterator trait的结构体,每次迭代都会返回一个char类型的值。 ```javascript fn main() { let slice = "Hello, 霸都"; for c in slice.chars() { println!("{}", c); } } ``` 另外,字符串切片还包括非常多实用的方法。 is_empty():检查字符串切片是否为空。 bytes():返回一个迭代器,可以遍历字符串字节。 starts_with(\&prefix)、ends_with(\&suffix):检查字符串切片是否以指定前缀或后缀开始/结束。 find(subslice):查找子字符串,并返回其索引(如果存在);否则,返回None。 contains(char) 、contains(\&str):检查字符串切片中是否存在指定字符或子字符串。 split(char)、split_whitespace():根据指定分隔符创建迭代器,每次迭代返回一个新字符串切片。 trim()、trim_start()、trim_end():移除字符串切片开头、结尾处的空白字符。 to_lowercase()、to_uppercase():转换为小写或大写字母形式。 这些方法具体如何使用,可参考下面的示例代码。 ```rust fn main() { let slice: &str = ""; assert!(slice.is_empty()); for c in "Hello, 中国".chars() { println!("{}", c); } for byte in "hello, 中国".bytes() { println!("{}", byte); } let slice: &str = "Hello, CSDN"; assert!(slice.starts_with("Hello")); assert!(slice.ends_with("CSDN")); let index = "Hello, CSDN".find(","); assert_eq!(index, Some(5)); let contains1 = "Hello, CSDN".contains("Hello"); let contains2 = "Hello, CSDN".contains('D'); assert!(contains1 && contains2); // 输出:Hello和CSDN for word in "Hello, CSDN".split(',') { println!("{}", word.trim()); } let trimmed = " Hello, CSDN ".trim(); assert_eq!(trimmed, "Hello, CSDN"); let lowercased = "Hello, CSDN".to_lowercase(); assert_eq!(lowercased, "hello, csdn"); } ``` ### 总结 最后,我们来总结一下切片的特性,主要有以下几点。 1、引用类型:切片是一种引用类型,它允许我们以引用的方式访问连续内存的数据。 2、没有所有权:切片本身并不拥有数据,而是对数据的一种引用或视图。这意味着切片不会复制数据,而是直接引用原始数据,没有拷贝数据的额外开销。 3、连续内存:切片引用的是一段连续的内存分配,而不是整个集合。这使得切片能够安全、高效地访问数组,而无需复制数据。 4、可变与不可变:切片可以是可变的,也可以是不可变的,这取决于它们所引用的数据的可变性。可变切片允许修改引用的数据,而不可变切片则不允许。 5、索引与迭代:切片可以使用数字索引来访问其中的元素,索引从0开始计数。此外,切片还支持迭代,可以使用迭代器来遍历切片中的元素。

相关推荐
int82 小时前
error: failed to run custom build command for `yeslogic-fontconfig-sys v6.0.0`
rust
pumpkin8451411 小时前
学习笔记十二——Rust 高阶函数彻底入门(超详细过程解析 + 每步数值追踪)
笔记·学习·rust
柑木12 小时前
Rust-开发应用-enum转String常见解法
rust
维维酱13 小时前
Rust drop 函数
rust
Code blocks13 小时前
Rust-引用借用规则
开发语言·后端·rust
Hello.Reader13 小时前
Rust + WebAssembly 性能剖析指南
开发语言·rust·wasm
Linux编程用C1 天前
Rust编程学习(一): 变量与数据类型
开发语言·后端·rust
维维酱2 天前
Rust DerefMut
rust
无名之逆2 天前
高性能文件上传服务
java·服务器·网络·http·rust