面向 GPT4 学习 Rust
Published by powerfulyang on Apr 25, 2023
pub(crate) 和 pub 区别
在 Rust 中,pub(crate)
和 pub
关键字用于控制项目中的可见性(或称作访问控制)。它们之间的区别在于它们允许其他模块访问的范围不同。
pub
:当你使用pub
关键字修饰一个项(如函数、结构体、枚举等)时,这意味着该项对整个项目及其依赖该项目的其他项目都是可见的。换句话说,它具有公共可见性,任何外部模块或库都可以访问它。pub(crate)
:当你使用pub(crate)
关键字修饰一个项时,它表示该项仅在当前 crate(包)中可见。这意味着该项对 crate 内的所有模块可见,但不能被其他依赖于此 crate 的项目访问。它具有 crate 级别的可见性,是一个更严格的访问控制。
使用 pub(crate)
而不是 pub
的一个主要原因是,当你想在当前 crate 的多个模块之间共享某个项,但不希望它被外部的 crate 使用时,可以使用 pub(crate)
。这有助于维护封装性和避免不必要的公共 API 暴露。
for i in (0..=31).rev() 和 for i in (0..31).rev() 的区别
-
(0..=31).rev()
创建了一个从 0 到 31(包括 31)的逆向范围。这意味着迭代将从 31 开始,然后递减到 0。这是一个闭区间,因为它包括了边界值 31。 -
(0..32).rev()
创建了一个从 0 到 32(不包括 32)的逆向范围。这意味着迭代将从 31 开始,然后递减到 0。这是一个左闭右开区间,因为它不包括边界值 32。
在第一个代码片段中,使用 ..= 语法表示闭区间,而在第二个代码片段中,使用 .. 语法表示左闭右开区间。
Rust 如何 进行单元测试
在 Rust 中,进行单元测试相对简单。通常,您会在源代码文件(例如 lib.rs
或 main.rs
)中编写测试函数。以下是进行单元测试的基本步骤:
- 在您要编写测试的源代码文件中,添加一个名为
tests
的模块,并使用#[cfg(test)]
属性配置它仅在测试配置中编译。这样可以确保在正常构建时不会编译和运行测试代码。
1#[cfg(test)]
2mod tests {
3 // 测试代码将在这里
4}
- 在
tests
模块中,为要测试的函数编写测试函数。测试函数应该以test_
为前缀,并使用#[test]
属性标记。在测试函数内部,您可以使用assert!
、assert_eq!
和assert_ne!
等宏来验证结果是否符合预期。
例如,假设您有一个名为 add
的函数:
1fn add(a: i32, b: i32) -> i32 {
2 a + b
3}
您可以编写如下单元测试:
1#[cfg(test)]
2mod tests {
3 use super::*; // 引入当前作用域的所有内容,包括 `add` 函数
4
5 #[test]
6 fn test_add() {
7 assert_eq!(add(1, 2), 3);
8 assert_eq!(add(0, 0), 0);
9 assert_eq!(add(-1, 1), 0);
10 }
11}
- 使用
cargo test
命令运行测试。Cargo 将自动找到并运行所有使用#[test]
属性标记的测试函数。
在终端中键入以下命令:
1cargo test
如果测试成功,您将看到类似以下输出:
1running 1 test
2test tests::test_add ... ok
3
4test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s
这意味着所有测试均已通过。
单元测试是 Rust 中编写可靠代码的关键组成部分。通过编写测试来验证您的函数和模块,您可以确保代码的正确性和稳定性。
在 CLion 中使用 Live Templates 加速开发
- tmod
1#[cfg(test)]
2mod tests {
3 use super::*;
4
5
6}
- tfn
1#[cfg(test)]
2mod tests {
3 use super::*;
4
5 #[test]
6 fn test() {
7
8 }
9}
#[derive(Default)]
在 Rust 编程语言中,#[derive(Default)]
是一个派生宏(derive macro),用于自动实现结构体或枚举的默认值。
通过在结构体或枚举上使用 #[derive(Default)]
,可以为其自动生成一个默认值。默认值是该类型的每个字段或成员的默认值的组合。
例如,考虑以下结构体的示例:
1#[derive(Default)]
2struct Person {
3 name: String,
4 age: u32,
5 is_student: bool,
6}
通过在结构体上使用 #[derive(Default)]
,可以为 Person
结构体自动生成一个默认值。默认值将使用每个字段的默认值:
1fn main() {
2 let person: Person = Default::default();
3 println!("Name: {}", person.name); // 输出: Name:
4 println!("Age: {}", person.age); // 输出: Age: 0
5 println!("Is Student: {}", person.is_student); // 输出: Is Student: false
6}
在上述示例中,我们创建了一个 Person
结构体的实例 person
,并访问其字段。由于我们使用了 #[derive(Default)]
,因此 person
的字段被初始化为默认值。对于 String
类型的字段 name
,默认值是一个空字符串 ""
;对于 u32
类型的字段 age
,默认值是 0
;对于 bool
类型的字段 is_student
,默认值是 false
。
#[derive(Default)]
简化了结构体或枚举的默认值的实现,使得代码更简洁,并避免了手动编写默认值的重复工作。
usize
usize
和 i32
是 Rust 编程语言中的两种整数类型,它们在表示方式和用途上有一些差别。
- 符号性(Signedness):
i32
是有符号整数类型,可以表示正数、负数和零。而usize
是无符号整数类型,只能表示非负数和零。因此,usize
可用于表示数组索引、集合大小和内存地址等只能是非负数的情况。 - 大小:
i32
的大小是固定的,它占用 32 位(4 字节)内存空间,无论在何种计算机架构上。而usize
的大小取决于当前的计算机架构,通常为 32 位或 64 位。在 32 位架构上,usize
大小为 32 位(4 字节),在 64 位架构上,usize
大小为 64 位(8 字节)。 - 取值范围:由于
usize
是无符号整数类型,它可以表示的最大值是比i32
更大的正整数。在 32 位架构上,usize
的最大值是4294967295
,而i32
的最大值是2147483647
。
由于 usize
和 i32
有不同的符号性和大小,因此在使用它们时需要根据具体的需求和上下文来选择合适的类型。通常情况下,usize
适用于索引、集合大小和内存相关的操作,而 i32
适用于一般的整数运算和表示。
#[derive(Debug)]
#[derive(Debug)]
是 Rust 编程语言中的一个派生宏(derive macro),用于为自定义的结构体或枚举类型自动生成实现 Debug
trait 的代码。
Debug
trait 是 Rust 标准库提供的一个 trait,用于格式化输出调试信息。通过实现 Debug
trait,我们可以使用调试格式化字符串打印自定义类型的值。
使用 #[derive(Debug)]
宏,我们可以简单地为结构体或枚举类型自动生成 Debug
trait 的实现,而无需手动编写代码。
例如,考虑以下结构体的示例:
1#[derive(Debug)]
2struct Person {
3 name: String,
4 age: u32,
5 is_student: bool,
6}
通过在结构体上使用 #[derive(Debug)]
,我们为 Person
结构体自动生成了 Debug
trait 的实现。这使得我们可以直接使用调试格式化字符串打印 Person
类型的值:
1fn main() {
2 let person = Person {
3 name: "Alice".to_string(),
4 age: 25,
5 is_student: true,
6 };
7
8 println!("{:?}", person);
9}
在上述示例中,我们创建了一个 Person
结构体的实例 person
,并通过使用 println!("{:?}", person)
来打印它的调试信息。由于我们使用了 #[derive(Debug)]
,因此编译器会自动生成打印 person
的调试格式化字符串。输出结果将类似于以下内容:
1Person { name: "Alice", age: 25, is_student: true }
通过自动实现 Debug
trait,我们可以方便地打印自定义类型的调试信息,用于调试和排查问题。