心学从0开始学习rust-十万个为什么篇章(持续更新篇章)

问答环节

1.const x = 1;和let x = 1有何区别呢,const申请的是全局变量所以会一直有效对吗?

const 声明的常量具有全局作用域,但它们不能直接在函数内部声明。常量通常用于定义整个程序中使用的值,如配置常量或数学常量。
let 声明的变量具有局部作用域,它们只能在声明它们的代码块或函数内部使用。
const 声明的常量没有生命周期的概念,因为它们在编译时就已经确定,并且存储在程序的二进制代码中。
let 声明的变量具有生命周期,它们的生命周期由 Rust 的所有权系统管理。变量的生命周期从声明点开始,到它们离开作用域结束。

2.#[derive(Serialize)]到底是怎么工作的?

在 Rust 中,#[derive(Serialize)] 是一个属性宏(attribute macro),用于自动结构体或枚举类型实现 serde::Serialize trait。这个 trait 是来自于 serde 库的,它是一个流行的 Rust 序列化框架,允许你将 Rust 数据结构转换为各种格式,如 JSON、YAML、XML 等。
当你在结构体或枚举上使用 #[derive(Serialize)] 时,Rust 编译器会自动生成实现 Serialize trait 所需的代码。这意味着你可以在不手动编写序列化逻辑的情况下,将你的数据结构转换为字符串或其他序列化格式。
如果结构体不在这个宏下声明就需要手动实现序列化方法
反序列化和序列化一般会同时声明:

use serde_derive::{Deserialize, Serialize}; 
#[derive(Serialize)]
struct SubscriptionMsg {time: u64,channel: &'static str,event: &'static str,payload: Vec<&'static str>,
}// WebSocket服务器返回的数据结构
#[derive(Deserialize, Debug)]
struct WebSocketResponse {// 根据实际情况定义result: bool,
}
use serde::{Deserialize};#[derive(Deserialize)]
struct User {name: String,age: u8,email: Option<String>,
}fn main() {let data = r#"{"name": "Alice","age": 30,"email": "alice@example.com"}"#;let user: User = serde_json::from_str(data).unwrap();println!("Name: {}", user.name);println!("Age: {}", user.age);println!("Email: {}", user.email.unwrap_or_default());
}

3.为什么使用connect_async建立websocket连接的时候是let (ws_stream, _) =connect_async(WS_URL).await?;而不是let ws_stream = connect_async(WS_URL).await?;

解答:
在这种情况下,使用 let (ws_stream, _) = connect_async(WS_URL).await?; 的形式是为了忽略 connect_async 返回的连接结果的一部分。具体来说,connect_async 函数返回一个 Result,其中包含了建立的 WebSocket 连接(WebSocketStream),以及一个用于处理连接结果的对象(通常是 ClientHandshake)。在 let (ws_stream, ) = connect_async(WS_URL).await?; 中, 是一个通配符,用于匹配 ClientHandshake 对象。由于我们通常不需要使用 ClientHandshake 对象,因此可以使用 _ 进行忽略。
这里有关的内容是模式匹配

4.let (mut write, mut read) = ws_stream.split();这个是在干什么呢?

这行代码在 Rust 中的 WebSocket 编程中常用于分离 WebSocket 连接的读写部分,以便于分别进行写入和读取操作。
具体来说,split() 方法是 WebSocketStream 类型的一个方法,用于将一个完整的 WebSocket 连接分为两个部分:一个负责写入数据的部分,一个负责读取数据的部分。
在这行代码中,let (mut write, mut read) = ws_stream.split(); 将 ws_stream 分为 write 和 read 两个部分,分别代表写入和读取数据的操作。mut 关键字表示这两个变量是可变的,因为在通常情况下,你会对这两个部分进行读写操作。
分离 WebSocket 连接的读写部分可以方便地进行并发操作,比如在一个线程中进行数据的读取,而在另一个线程中进行数据的写入,这样可以提高程序的并发性能。

5.Utc::now().timestamp() as u64什么意思?

这段代码是一个例子,它使用了特定编程语言或框架提供的函数或方法。看起来像是Rust语言中的一行代码。
Utc::now() 是Rust语言中 chrono 库的一部分,用于获取当前的UTC时间。
.timestamp() 是 chrono 库提供的 DateTime 结构体的方法之一,它将日期时间转换为UNIX时间戳,即从1970年1月1日UTC开始的秒数。
as u64 是类型转换,它将UNIX时间戳从默认的 i64 类型(有符号64位整数)转换为 u64 类型(无符号64位整数),因为UNIX时间戳可以是负数,但通常我们更关心非负数。
综合起来,这行代码的作用是获取当前UTC时间,并将其转换为一个64位无符号整数(u64),表示自1970年1月1日以来的秒数

6.什么是 tokio_tungstenite::tungstenite::protocol::Message;

tokio_tungstenite::tungstenite::protocol::Message 是 Rust 编程语言中的一个类型,它来自于 tokio_tungstenite crate,是一个基于 Tokio 的 WebSocket 库。这个类型代表了 WebSocket 连接中可以发送或接收的不同类型的消息。通常,它包括以下变体:
Text(String): 表示文本消息。
Binary(Vec): 表示二进制消息。
Ping(Vec): 表示 ping 控制帧。
Pong(Vec): 表示 pong 控制帧。
Close(Option): 表示关闭控制帧,可选地包含关闭原因。
这些变体封装了 WebSocket 连接中可以传输的不同类型的数据。

7.r# #中间包裹json数据是为了什么?

json数据中会有""这样的符号,会造成歧义,如果包裹在r##里面就直接当作字符串去进行处理这个json数据,否则的话则需要使用转义字符来防止歧义的发生。

let data = r#"{"name": "Alice","age": 30,"email": "alice@example.com"}
"#;let data = "{\"name\": \"Alice\", \"age\": 30, \"email\": \"alice@example.com\"}";

上下两段的效果是等价的

8.&'static str

不可变性:由于字符串字面量是不可变的,所以 &'static str 引用也是不可变的。你不能通过这个引用来修改字符串的内容。
生命周期:'static 生命周期是 Rust 中所有其他生命周期的超集。这意味着任何 'static 生命周期的引用都可以在任何其他生命周期上下文中安全使用,无需担心生命周期问题。
内存管理:因为字符串字面量存储在程序的二进制文件中,所以它们占用的空间是固定的,并且在程序的整个生命周期内都不会改变。这使得 &'static str 非常适合用于那些需要长期存在且不会改变的数据。
性能:由于不需要在运行时分配和释放内存,使用 &'static str 可以提高性能,尤其是在创建大量字符串引用时。

9.什么叫做工作窃取?

每一个工作单元都有一个任务队列,如果自己的任务做完了难道让cpu空闲吗?这显然是不合理的,因此去访问其他工作单元的任务队列进行并发执行,当然在这个过程中需要注意mutex对任务进行加锁防止产生冲突。

10.pin的某些用法

pin可以把数据固定在stack中,观察如下代码

use tokio::pin;async fn my_async_fn() {// async logic here
}#[tokio::main]
async fn main() {let future = my_async_fn();pin!(future);(&mut future).await;
}

这个future被固定在了stack中,按理说一个future只能够被.await调用一次,但是一旦固定了这个future,就可以被await多次调用。
future是惰性的,如果你不使用await进行调用的话,他的一系列操作是不会执行的

11. select!的简单理解

首先观察如下代码

use tokio;// 假设这是我们想要并发执行的两个异步任务
async fn task1() -> Result<(), Box<dyn std::error::Error>> {tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;Ok(())
}async fn task2() -> Result<(), Box<dyn std::error::Error>> {tokio::time::sleep(tokio::time::Duration::from_secs(3)).await;Ok(())
}#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {// 启动两个异步任务let handle1 = tokio::spawn(task1());let handle2 = tokio::spawn(task2());// 使用 select! 宏等待这两个任务中的任何一个完成select! {_ = handle1 => {println!("Task 1 completed");},_ = handle2 => {println!("Task 2 completed");},}// 这里我们不需要再次等待 handle1 或 handle2,因为 select! 宏已经处理了其中一个任务的完成// 如果我们想要等待另一个任务完成,我们可以再次使用 select! 宏或者 simply await the remaining handle// 例如,等待另一个任务完成if handle1.is_alive() {handle1.await.unwrap();} else {handle2.await.unwrap();}Ok(())
}

select会等待某个任务的先执行完成并进行相应处理。
1. 竞态条件处理
在某些情况下,你可能需要在多个异步操作之间进行选择,例如,当两个异步任务同时尝试访问共享资源时,你可能需要决定哪个任务应该先执行。select! 宏可以帮助你实现这种逻辑,确保资源在任何给定时间只被一个任务访问。
2. 并发流处理
当你使用 Stream 处理数据流时,你可能想要同时处理多个数据流。select! 宏允许你等待来自多个数据流的事件,并根据哪个流先产生数据来做出决策。
3. 服务多个客户端
在编写网络服务时,你可能需要同时处理多个客户端的连接。使用 select! 宏,你可以等待来自多个客户端的操作,并为每个操作提供服务,而不会阻塞其他客户端。
4. 超时处理
select! 宏可以用于实现超时逻辑。例如,你可以同时等待一个异步操作完成和一个超时发生,然后根据哪个先发生来执行相应的操作。
5. 并行任务执行
当你需要并行执行多个任务并根据它们的结果做出决策时,select! 宏可以非常有用。你可以启动多个异步任务,并使用 select! 宏等待它们中的任何一个完成。
==select!==是异步的,在等待的过程中并不会影响其他进程的进行。

12.与select几乎同父异母的join

当你有多个 Future 需要完成,并且需要它们的输出来继续执行后续操作时,join! 宏允许你等待所有的 Future 完成并收集它们的结果。
看如下代码

async fn future1() -> i32 {// 异步操作返回一个 i3242
}async fn future2() -> String {// 异步操作返回一个 String"Hello".to_string()
}#[tokio::main]
async fn main() {let result1 = future1();let result2 = future2();let (res1, res2) = tokio::join!(result1, result2);println!("Result 1: {}, Result 2: {}", res1, res2);
}

join和select的区别在于,select在遇到一个任务结束时就会结束,但是join会等待语句中的任务全部完成。
join同样是异步的,也就是等待任务执行的过程中并不会阻塞其他任务执行

13、关于lazy_static

lazy_static 是 Rust 语言中的一个 crate,它允许你在结构体中创建静态变量,而这些变量将会在第一次被使用时进行初始化这个特性在需要延迟加载或者减少启动时间的场景中非常有用,尤其是当你有一个重量级的初始化过程或者初始化过程依赖于运行时环境的时候。

use lazy_static::lazy_static;lazy_static! {static ref MY_STATIC: Vec<i32> = {let mut v = Vec::new();for i in 0..1000 {v.push(i);}v};
}fn main() {// 访问静态变量,这将触发初始化println!("First element is: {}", MY_STATIC[0]);
}

14.unwrap_or_else

unwrap_or_else 是 Rust 标准库中 Result 和 Option 类型提供的一个方法,它为错误处理提供了一种灵活的方式。当调用 unwrap_or_else 方法时,如果 Result 或 Option 是 Ok 或 Some,则返回其值;如果是 Err 或 None,则执行提供的函数,并返回该函数的返回值。
在这里插入图片描述

15 mpsc的rx为什么是mut?

在 Rust 中,mpsc(多生产者单消费者)通道的接收端 Receiver 被设计为可变的(mut),这是因为接收操作可能会消耗(consume)通道中的消息,从而改变通道的状态。在 Rust 的所有权和借用规则下,这样的操作需要可变性。
当一个消息被发送到 mpsc 通道时,它被放入一个内部缓冲区。接收端 Receiver 负责从这个缓冲区中取出消息。每次取出消息后,该消息就不再存在于通道中了,因此接收端必须具有可变性来改变这个状态。因此,Receiver 必须是可变的,以便能够从通道中移除消息并更新通道的内部状态。这是 Rust 语言设计的一部分,旨在通过所有权和借用规则来保证内存安全和线程安全。

16.如果接收端的rx被多线程共享,多线程访问队列时会同时获取同一份数据吗?

当一个 mpsc 通道的接收端 rx 被多个线程共享时,每个线程都会拥有 rx 的一个独立克隆(clone),这些克隆都是对同一个底层队列的引用。然而,尽管多个线程可以同时接收来自通道的消息,但每次从通道接收消息的操作是原子的,这意味着在任何给定时刻,只有一个线程可以从通道中接收消息。
这是因为 mpsc 接收端 Receiver 的实现通常会使用内部锁或其他同步机制来确保并发安全。当一个线程尝试从 Receiver 中接收消息时,它会尝试获取锁;如果锁已经被其他线程持有,则当前线程会被阻塞,直到锁可用。这样可以保证消息不会被多个线程同时读取,从而避免了数据竞争和不一致的状态。

17.println(“{}”,x)和println(“{}”,x)的区别?

在 Rust 中,println! 宏是用来打印输出的,它可以使用不同的格式化占位符来指定如何显示输出的值。当你使用 {:?} 作为格式化占位符时,它会调用值的 Debug 格式方法,而使用 {} 作为格式化占位符时,它会调用值的 Display 格式方法。
对于字符串切片(&str 类型),Debug 格式方法会将字符串包围在双引号中,并在前面加上一个反斜杠,这是因为 Debug 格式旨在提供一种稳定且易于识别的输出,用于调试和开发目的。所以当你使用 {:?} 打印字符串时,它会以 “BTC_USDT” 的形式显示,这里的反斜杠是转义字符,表示后面的双引号是字符串的一部分,而不是字符串的结束。
另一方面,Display 格式方法旨在提供一种适合终端用户查看的输出。它通常会省略调试信息中的额外信息,如双引号和转义字符。因此,当你使用 {} 打印字符串时,它会直接显示字符串的内容,即 “BTC_USDT”。

18.我的collect方法构建一个由(f64,f64)这个元组构成的vector数组,collect方法可以收集None吗

实际上,collect方法并不会收集None值。在Rust中,collect方法是用来将迭代器中的元素收集到某种集合类型的。当迭代器中的元素是Option类型时,collect方法会将Some(T)值收集到集合中,而None值会被忽略,不会包含在最终的集合中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/258.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

tcp网络编程——2

1.一个服务器只能有一个客户端连接&#xff08;下面代码&#xff09; ​​​​​​​tcp网络编程&#xff08;基础&#xff09;-CSDN博客 2.一个服务器可以有多个客户端连接&#xff08;多线程&#xff09; server端创建多个线程&#xff0c;每个线程与不同的client端建立连…

浅写个登录(无js文件)

全部代码如下&#xff0c;无需编写wxss文件&#xff0c;渲染都在style里面&#xff1a; <view style"height: 250rpx;width: 100%;"> <!-- 背景图片 --><view style"position: absolute; background-color: antiquewhite; height: 250rpx;width…

代码随想录-算法训练营day16【二叉树03:二叉树的最大深度、二叉树的最小深度、完全二叉树的节点个数】

代码随想录-035期-算法训练营【博客笔记汇总表】-CSDN博客 第六章 二叉树part03今日内容&#xff1a; ● 104.二叉树的最大深度 559.n叉树的最大深度 ● 111.二叉树的最小深度 ● 222.完全二叉树的节点个数迭代法&#xff0c;大家可以直接过&#xff0c;二刷有精力的时候 再去…

IDEA中Docker相关操作的使用教程

一、引言 Docker作为当前最流行的容器化技术&#xff0c;极大地简化了应用的部署和管理。而IntelliJ IDEA作为一款强大的集成开发环境&#xff0c;也提供了对Docker的集成支持。本文将介绍如何在IDEA中配置和使用Docker&#xff0c;包括远程访问配置、服务连接、Dockerfile编写…

【C语言】冒泡排序算法详解

目录 一、算法原理二、算法分析时间复杂度空间复杂度稳定性 三、C语言实现四、Python实现 冒泡排序&#xff08;Bubble Sort&#xff09;是一种基础的排序算法。它重复地遍历要排序的数列&#xff0c;一次比较两个元素&#xff0c;如果他们的顺序错误就把他们交换过来。遍历数列…

Go读取文件n行的思路之旅

【问题】最近想在一个10G的文件上读取最后100行数据&#xff0c;用了多种方式去实现&#xff0c;发现还是逆向读取比较香一点 【方法】分别尝试了两种方式&#xff1a;双端队列和逆读文件   在这里我就直接把结论放在文章前面 双端队列&#xff1a;适用于文件数据不大的情况…

微信小程序开发笔记

微信小程序开发笔记 1 微信小程序的项目结构 2 页面组成 一个微信小程序是由一个或多个页面组成的&#xff0c;这些页面被存放在pages目录中。下面以pages 目录下的index页面为例展示其组成部分&#xff0c;index页面的组成部分如下图所示。 由上图可知&#xff0c;index页面…

hbase-2.2.7分布式搭建

一、下载上传解压 1.在官网或者云镜像网站下载jar包 华为云镜像站&#xff1a;Index of apache-local/hbase/2.2.7 2.上传到linux并解压 tar -zxvf hbase-2.2.7-bin.tar.gz -C /usr/locol/soft 二、配置环境变量 1. vim /etc/profile export HBASE_HOME/usr/local/soft/h…

教授 Avi Wigderson荣获2023年图灵奖

2023年图灵奖&#xff0c;最近刚刚颁给普林斯顿数学教授 Avi Wigderson&#xff01;作为理论计算机科学领域的领军人物&#xff0c;他对于理解计算中的随机性和伪随机性的作用&#xff0c;作出了开创性贡献。 Avi Wigderson因其在计算复杂性理论、随机性与算法等领域的开创性贡…

【数据结构】二分查找

1.概念 二分查找&#xff08;Binary Search&#xff09;是一种高效的查找算法&#xff0c;它在一个有序数组中查找特定的元素。二分查找的工作原理是不断将数组分成两半&#xff0c;比较中间元素与目标值&#xff0c;根据比较结果选择左半部分或右半部分继续查找&#xff0c;直…

前端三剑客 HTML+CSS+JavaScript ② HTML相关概念

他们这样形容我 是暴雨浇不灭的火 —— 24.4.18 学习目标 理解 HTML的概念 HTML的分类 HTML的关系 HTML的语义化 应用 HTML骨架格式 sublime基本使用 一、HTML初识 HTML指的是超文本标记语言&#xff0c;是用来描述网页的一种语言 超文本&#xff1a;暂且理解为“超级的文本”&…

【opencv】dnn示例-segmentation.cpp 通过深度学习模型对图像进行实时语义分割

模型下载地址&#xff1a; http://dl.caffe.berkeleyvision.org/ 配置文件下载&#xff1a; https://github.com/opencv/opencv_extra/tree/4.x/testdata/dnn 该段代码是一个利用深度学习进行语义分割的OpenCV应用实例。下面将详细解释代码的功能和方法。 引入库 引入了一些必要…

PyTorch转ScriptModule的问题记录

文章目录 本文记录了转ScriptModule时遇到的一系列问题如何转ScriptModule?遇到的坑Expected a value of type Tensor for argument self but instead found type Optional[Tensor].Expected integer literal for index but got a variable or non-integer. ModuleList/Sequen…

(最详细)关于List和Set的区别与应用

关于List与Set的区别 List和Set都继承自Collection接口&#xff1b; List接口的实现类有三个&#xff1a;LinkedList、ArrayList、Vector。Set接口的实现类有两个&#xff1a;HashSet(底层由HashMap实现)、LinkedHashSet。 在List中&#xff0c;List.add()是基于数组的形式来添…

内部类

一.概念 当一个事物内部&#xff0c;还有一个部分需要一个完整的结构进行描述&#xff0c;而这个内部的完整的结构又只为外部事物提供服务&#xff0c;那么将这个内部的完整结构最好使用内部类。在Java中&#xff0c;可以将一个类定义在另一个类或者一个方法内部&#xff0c;前…

记录OCEAN报错信息和对应解决方案

记录OCEAN代码报错信息和对应我代码部分解决方案 Error fprintf/sprintf: format spec. incompatible with data - “Format is ‘GBW IS %e\n’, argument #1 is nil”使用gainBwProd()测得GBW返回值为nil&#xff0c;导致printf出错添加检测代码 if(GBW nil printf("GB…

将gdip-yolo集成到yolov9模型项目中(支持预训练的yolov9模型)

1、yolov9模型概述 1.1 yolov9 YOLOv9意味着实时目标检测的重大进步&#xff0c;引入了可编程梯度信息&#xff08;PGI&#xff09;和通用高效层聚合网络&#xff08;GELAN&#xff09;等开创性技术。该模型在效率、准确性和适应性方面取得了显著改进&#xff0c;在MS COCO数…

GNU Radio使用Python Block实现模块运行时间间隔获取

文章目录 前言一、timestamp_sender 模块二、timestamp_receiver 模块三、测试 前言 GNU Radio 中没有实现测量两个模块之间的时间测量模块&#xff0c;本文记录一下通过 python block 制作一个很简单的测时 block。 一、timestamp_sender 模块 使用 python block 做一个发送…

【python】super()函数的用法详解!

今天分享一个我在实际项目中用到过的super()函数&#xff0c;来说说该函数的主要功能是什么&#xff0c;简单来说&#xff0c;super()函数是用来做调用父类的一个方法。 super() 是用来解决多重继承问题的&#xff0c;直接用类名调用父类方法在使用单继承的时候没问题&#xf…

外包干了30天,技术倒退明显

先说情况&#xff0c;大专毕业&#xff0c;18年通过校招进入湖南某软件公司&#xff0c;干了接近6年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落&#xff01; 而我已经在一个企业干了四年的功能…