-
async-std 和 tokio async-std 和 tokio 都是 Rust 中用于异步编程的库。它们的主要区别在于,async-std 更注重提供类似于 Rust 标准库的 API 和使用习惯,而 tokio 则提供了更为灵活的 API 和自定义能力。在实际使用中,如果需要快速上手,可以选择 async-std;如果需要更高的灵活性和自定义能力,可以选择 tokio。
-
tokio 和 actix tokio 是一个异步编程框架,提供了用于异步 I/O 操作的基础设施,例如事件循环和异步任务的执行器。而 actix 是一个基于 tokio 的异步 Web 框架,提供了 Web 开发的相关功能和工具,例如 HTTP 服务器和路由等。
-
native-tls 和 rustls native-tls 和 rustls 都是 Rust 中用于 TLS 加密和解密的库。它们的主要区别在于,native-tls 使用操作系统的本地 TLS 库,例如 OpenSSL,而 rustls 是一个纯 Rust 实现的 TLS 库。在实际使用中,如果需要更高的性能和对操作系统 TLS 库的依赖度较低,可以选择 rustls;如果需要更广泛的兼容性和对操作系统 TLS 库的支持,可以选择 native-tls。
总的来说,async-std、tokio、actix、native-tls、rustls 这些库和框架都是 Rust 中非常常用的工具,用于异步编程和网络编程。它们之间的区别和联系需要根据具体的使用场景和需求来选择。
建议阅读的文档: 九层之台,起于累土
解答:
在Rust中,变量默认是不可变,如果想要一个变量可变必须要在声明变量的时候显式地加上mut
标志。这也就是在Rust中声明变量被称之为绑定
变量的原因。其主要目的是为了考虑安全,变化是安全的重要源头之一。
let a = 100;
// a += 1; //放开这行代码,无法通过编译,因为变量`a`默认不可变。
let mut b = 100; // 用`mut`对变量`a` 作显式标浅
b = b + 1; // ok
解答: 所谓的变量遮蔽(shadow),是指在同一上下文中,可以对已经声明或定义的变量进行重复的声明或定义,新的变量声明或定义后,原变量失效。新的变量与原变量的关系是,新变量仅仅在名称上与原变量相同,这就意味着新变量的类型可以不同于原变量。
let s = String:from("abc");
println!("{s}");
let s = 100; //此处,对原变量s进行了遮蔽;
s += 20;
...
解答:
- 常量,是指程序整个的生命周期内都是不可变的量,用来表示全局范围内可被多处使用的不变量,比如一个星期有7天这种永恒的量。常量通常是在编译时就被包含在程序二进制文件中,程序加载内在后也会被单独存放在类型常量或者是静态的内存区域,该内存区域是只读的。
- 常量在定义时,不适应类型的自动推断,必须显式地标注其类型。
//const DAYS_IN_WEEK = 7; //Error const DAYS_IN_WEEK: u8 = 7; // ok
- 常量与变量的区别: 变量,通常是在函数内部的局部空间进行定义的,然后在运行的时候,实时地分配在栈空间里面。可见,变量的默认不可变性设计,主要是出于对安全的考究,其与常量的目的与内存管理机制都有着本质区别。
解答:
Rust中的基本数据类型,主要有整数
、浮点数
、字符
、布尔
、元组
、数组
等。
分为有符号整数与无符号整数,有符号数用u
开头,无符号数用i
开头,同时有长度信息(8、16、32、64、128...),比如i32
表示有符号且长度为32位的整数,u32
表示无符号且长度为32的整数。
- 在绑定变量的时候,如果不显式的指定整数的类型,编译器会自动推断为
i32
类型。 - 还有一种特殊的整型:
usize
与isize
,其长度与目标机器的字长长度一致。如果是32机器,其长度是32位,如果是64位机器,其长度是64位。 - 不同长度的类型在进行转换时,要考虑到安全性问题。一般来说,把一个长度大的数转换成长度小的类型是不安全的,因为发生一部分二进制位被丢失的情况(即所谓的窄化),相反情况是安全的。
分为32位与64位,分别为f32
与f64
。如果未显式指定类型,编译器会自动推断为f64
类型。
字符的类型用char
声明,当右值为字面量的时候,用单引号包裹,如果是双引号会被认为是字符串。
- 字符内部的数值编码是
UniCode
,它所表达的范围特别广,不但可以表达键盘上可打印的字符,还包括各种表情符号、中文、韩文等等。 - 一个字符占用4个字节
布尔类型,用bool
表示,用于描述逻辑上的真假值,有true
和false
两种值。
- 占用一个字节
- bool类型是一个独立的类型,与其他类型之间的转换关系
元组是将多个类型的多个值组合到一个复合类型中的一种基本方式。元组的长度是固定的,声明后无法增长或缩小。
let tup: (i32, f64, u8) = (500,6.4,1); // 定义
println!("1st number is {}", tup.0); // 访问其中的分量
let (x, y, z) = tup;
println!("The value of y is: {}", y);
没有任何值的元组是一种特殊的类型,写作:()
,该类型称作为单元类型
,如果一个表达式没有返回值或者函数没有没有返回值,都被隐式地返回单元类型。
将多个类型相同的元素依次组合在一起,就是一个数组。 关于数组需要注意的点:
- 长度固定,一经定义就不可以改变
- 元素必须有相同的类型
- 元素之间,在物理上和逻辑上都是依次线性排列的
- 数组是存储在栈上
- 数组的长度也是类型一可或缺的部分,
[u8;3]
和[u8;4]
是不同的类型。
let arr: [i32;5] = [1, 2, 3, 4, 5];
println!("the 3th element of arr is : {}", arr[2]);
let mut arr = [0, 0, 0, 0];
arr[0] = 100;
println!("{:?}", arr);
要求:根据传入的布尔参数决定是升序还是降序。
解答:
fn bubble_sort(arr: &mut [i32], ascending: bool) {
let len = arr.len();
for i in 0..len - 1 {
for j in 0..len - i - 1 {
if (ascending && arr[j] > arr[j + 1]) || (!ascending && arr[j] < arr[j + 1]) {
/*
let tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
*/
arr.swap(j, j + 1);
}
}
}
}
#[test]
fn test_bubble_sort() {
let mut arr1 = [5, 3, 8, 6, 2];
bubble_sort(&mut arr1, true);
println!("升序排序: {:?}", arr1);
let mut arr2 = [5, 3, 8, 6, 2];
bubble_sort(&mut arr2, false);
println!("降序排序: {:?}", arr2);
}
fn main() {
let i1 = 100;
let i2 = i1;
println!("{}",i1);
}
fn main() {
let s1 = String:from("abc");
let s2 = s1;
println!("{}",s1);
}
fn f(s: String) {}
fn main() {
let s1 = String:from("abc");
f(s1);
println!("{}",s1);
}
fn main() {
let ref_a: &i32;
let b = *a;
println!("{}", b);
}
fn dangle() -> &i32 {
let a = 100;
&a
}
fn main() {
let ref_some = dangle();
println!("{}", *ref_some);
}
fn main() {
let mut a = 100;
let ref_a1 = &a;
println!("{}", *ref_a1);
let ref_a2 = &a;
println!("{}", *ref_a2);
let ref_a3 = &a;
println!("{}", *ref_a3);
let ref_mut_a1 = &mut a;
println!("{}", *ref_mut_a1);
println!("{}", *ref_a2); //如果把这行代码注释了,又是什么情况?
}
- name(字符串类型)
- age(整数类型)
- email(字符串类型)
- 定义这个结构体
- 为该结构体实现关联函数
new
,用以构建实例 - 对其字段分别实现
get
和set
关联方法。
解答:
// 1. 定义结构体 Person
#[derive(Debug, Clone)]
struct Person {
name: String,
age: u8,
email: String,
}
// 实现相关的方法和函数
impl Person {
fn new(name: String, age: u8, email: String) -> Self {
Self{name, age, email}
}
fn set_name(&mut self,name: String) {self.name = name;}
fn get_name(&self) -> &str {self.name.as_str()}
fn set_age(&mut self, age: u8) {self.age = age;}
fn get_age(&self) -> u8 {self.age}
fn set_email(&mut self, email: String) {self.email = email}
fn get_email(&self) -> &str {self.email.as_str()}
}
- NotStarted
- InProgress(包含一个表示进度的浮点数)
- Completed
- 定义该枚举类型
- 写一个关联方法
send_message
,返回类型为String
,使用 match 根据三种不同的变体打印相关的信息。对于InProgress类型,打印的信息中需要包含进度信息。
解答:
// 定义枚举 Status
enum Status {
NotStarted,
InProgress(f64),
Completed,
}
impl Status {
fn send_message(status: Status) ->String {
match status {
Status::NotStarted => "还没有开始".to_string(),
Status::InProgress(progress) => format!("正在进行中,当前进度为:{}", progress),
Status::Completed => "已经完成了".to_string(),
}
}
}
10.1 定义一个函数 find_person_by_email,接受一个 Vec 和一个 String 作为参数,返回一个 Option,表示在列表中找到的第一个匹配的Person。如果没有找到,返回 None。
解答:
fn find_person_by_email(people: Vec<Person>, email: String) -> Option<Person> {
for person in people {
if person.email == email {
return Some(person);
}
}
None
}
解答:
fn print_person_info(person_option: Option<Person>) {
match person_option {
Some(person) => println!("Found person: {:?}", person),
None => println!("Person not found"),
}
}
解答:
// 定义函数 group_people_by_age
use std::collections::HashMap;
fn group_people_by_age(people: Vec<Person>) -> HashMap<u8, Vec<Person>> {
let mut age_groups: HashMap<u8, Vec<Person>> = HashMap::new();
for person in people {
age_groups.entry(person.age).or_insert(Vec::new()).push(person);
}
age_groups
}
定义一个函数 to_uppercase_names,接受一个 Vec 作为参数,返回一个新的 Vec,其中包含所有 Person 的大写名字。 解答:
// 定义函数 to_uppercase_names
fn to_uppercase_names(people: Vec<Person>) -> Vec<String> {
let mut uppercase_names = Vec::new();
for person in people {
uppercase_names.push(person.name.to_uppercase());
}
uppercase_names
}
- 定义一个 Notification 特征,包含一个 send 方法,用于发送通知。
- 实现三个结构体 EmailNotification、SmsNotification 和 PushNotification,它们分别代表邮件通知、短信通知和推送通知,并为这些结构体实现 Notification 特征。
- 创建一个 NotificationSender 结构体,该结构体可以存储多个不同类型的通知,并能够调用它们的 send 方法来发送所有的通知。
- 使用泛型和特征对象来实现 NotificationSender 的通知存储。
参考答案:
// 定义 Notification 特征
trait Notification {
fn send(&self);
}
// 实现 EmailNotification 结构体
struct EmailNotification {
recipient: String,
subject: String,
body: String,
}
impl Notification for EmailNotification {
fn send(&self) {
println!("Sending email to {}: {}\n{}", self.recipient, self.subject, self.body);
}
}
// 实现 SmsNotification 结构体
struct SmsNotification {
phone_number: String,
message: String,
}
impl Notification for SmsNotification {
fn send(&self) {
println!("Sending SMS to {}: {}", self.phone_number, self.message);
}
}
// 实现 PushNotification 结构体
struct PushNotification {
device_id: String,
message: String,
}
impl Notification for PushNotification {
fn send(&self) {
println!("Sending push notification to {}: {}", self.device_id, self.message);
}
}
// 定义 NotificationSender 结构体,使用泛型
struct NotificationSender<T: Notification> {
notifications: Vec<T>,
}
impl<T: Notification> NotificationSender<T> {
fn new() -> Self {
NotificationSender {
notifications: Vec::new(),
}
}
fn add_notification(&mut self, notification: T) {
self.notifications.push(notification);
}
fn send_all(&self) {
for notification in &self.notifications {
notification.send();
}
}
}
// 使用特征对象的版本
struct DynNotificationSender {
notifications: Vec<Box<dyn Notification>>,
}
impl DynNotificationSender {
fn new() -> Self {
DynNotificationSender {
notifications: Vec::new(),
}
}
fn add_notification(&mut self, notification: Box<dyn Notification>) {
self.notifications.push(notification);
}
fn send_all(&self) {
for notification in &self.notifications {
notification.send();
}
}
}
fn main() {
// 使用泛型的 NotificationSender
let mut email_sender = NotificationSender::new();
email_sender.add_notification(EmailNotification {
recipient: String::from("[email protected]"),
subject: String::from("Welcome!"),
body: String::from("Thank you for signing up!"),
});
let mut sms_sender = NotificationSender::new();
sms_sender.add_notification(SmsNotification {
phone_number: String::from("123-456-7890"),
message: String::from("Your code is 1234."),
});
email_sender.send_all();
sms_sender.send_all();
// 使用特征对象的 DynNotificationSender
let mut dyn_sender = DynNotificationSender::new();
dyn_sender.add_notification(Box::new(EmailNotification {
recipient: String::from("[email protected]"),
subject: String::from("Welcome!"),
body: String::from("Thank you for signing up!"),
}));
dyn_sender.add_notification(Box::new(SmsNotification {
phone_number: String::from("123-456-7890"),
message: String::from("Your code is 1234."),
}));
dyn_sender.add_notification(Box::new(PushNotification {
device_id: String::from("device123"),
message: String::from("You have a new message."),
}));
dyn_sender.send_all();
}
fn apply_twice<F>(f: F, x: i32) -> i32
where
F: Fn(i32) -> i32,
{
// 在此实现
}
// 使用示例
fn main() {
let add_two = |x| x + 2;
let result = apply_twice(add_two, 5);
println!("{}", result); // 应输出 9
}
fn generate_adder(x: i32) -> impl Fn(i32) -> i32 {
// 在此实现
}
// 使用示例
fn main() {
let adder = generate_adder(5);
println!("{}", adder(3)); // 应输出 8
}
15. 编写一个函数 longest_with_an_announcement,它接受两个字符串切片和一个闭包作为参数。该闭包接受一个字符串切片,并返回一个字符串切片。函数返回两个字符串切片中较长的一个,并调用闭包来打印一个公告。
fn longest_with_an_announcement<'a, F>(x: &'a str, y: &'a str, ann: F) -> &'a str
where
F: Fn(&str) -> &str,
{
// 在此实现
}
// 使用示例
fn main() {
let x = "Hello, world!";
let y = "Hi, Rust!";
let announcement = |s: &str| {
println!("Announcement: {}", s);
s
};
let result = longest_with_an_announcement(x, y, announcement);
println!("The longest string is {}", result); // 应输出 "Hello, world!"
}
- calculator_core:核心计算逻辑。
- calculator_io:用于处理输入输出及错误管理。
calculator_core 包含基本的加减乘除功能,并在计算过程中可能返回自定义错误。
calculator_io 包含读取用户输入和输出结果的功能,并将 calculator_core 中的错误转换为用户友好的错误信息。
calculator_workspace/
├── Cargo.toml
├── calculator_core/
│ ├── Cargo.toml
│ └── src/
│ └── lib.rs
├── calculator_io/
│ ├── Cargo.toml
│ └── src/
│ └── lib.rs
└── tests/
└── integration_test.rs