784 words
闭包Rust中的闭包是一种匿名函数,可以捕获并存储环境中的变量,有点类似于Lambda表达式 闭包允许在其定义的作用域之外访问变量,并且可以在需要时将其移动或者借用给闭包 闭包在Rust中被广泛应用于函数式编程、并发编程和事件驱动编程等领域 比较适合用于短小的自定义逻辑的场景 1234let name = |参数列表| 表达式或语句块;let add = |x: i32| x + 1;let cal = |x, y, z| x * y + z;let res = cal(1, 2, 3); 捕获外部变量闭包可以捕获环境中的变量 123let x = 5;let add = |num| num + x;println!("{}", add(1)); // 输出 6 捕获变量有三种方法 传引用捕获(默认的,类似于 &T) 传值捕获(类似 T) 借用捕获(类似 &mut T) 1234567891011121314fn main(){ let mut num = 114; let print_num = ...
617 words
函数Rust的函数基本形式是这样的 123fn a_func(a: i32) -> i32 { } 函数名是蛇形风格,rust不在意函数的声明顺序,只需要有声明即可 函数参数必须声明参数名称和类型 语句与表达式这是rust非常重要的基础概念,我们可以认为函数体是由语句和表达式组成的 语句指的是执行某些操作并且没有返回值的步骤 例如 12let a = 5; // 正确let b = (let c = 1); // 错误 因为 let c = 1 没有返回值 表达式有计算步骤且有返回值,例如 123a = 7b + 1c * (a + b) rust认为{}内也是一个表达式 12345let a = 1;let c = { let b = 1; a + b}; 需要注意的是,表达式的返回值是 a + b,代表整个表达式的返回值,加上;之后就成了语句,就没有返回值了 返回值需要通过->声明返回值类型,但是rust不支持自动返回值类型判断 函数体表达式不允许有返回值,不能使用return ...
887 words
Rust输出到命令行输出到命令行主要可以使用println!()和print!() 1. 这两个都有!是因为他们并非是函数,而是宏,具体我们以后再介绍,普通函数是不需要加!的 2. 两者的区别是是否会在行尾加一个换行符 3. 具体使用方法和C语言的printf很像,但是是用{}作为占位符 4. 并且会自动识别和填充参数,字符也可以写在{}中 5. 也可以使用数字指定参数的位置 6. 转义字符是相同的,只有{或者}是需要对应的写两遍 例如 12345678fn main(){ let a = 12; let b = 24; println!("a is {}", a); println!("a is {a}"); println!("b is {1}, a is {0}", a, b); println!...
1k words
Rust语言介绍和猜数字游戏的实现Rust语言是一种系统编程语言,核心强调安全性、并发性以及高性能,由类似于C/C++的底层控制能力,性能也非常接近,Rust有一些特性 所有权系统,这个可以自动管理内存,无需垃圾回收器,保证数据的安全 零成本抽象,高层抽象不会带来运行时的开销,运行时的效率会很高 线程安全,在编译阶段就能防止数据竞争的问题 强类型语言,类型转换非常严格,提升代码的可靠性 cargo管理工具非常好用,简化项目的管理和依赖管理 cargo是什么cargo是rust的官方管理构建工具,一来可以创建项目、构建项目、运行项目,二来可以管理整个项目依赖的第三方库,cargo基本上涵盖了所有的第三方库,可以在www.crate.io中查看 一些常用的方法如下 1234567cargo new project_name # 创建rust项目cargo build # 构建项目生成可执行文件cargo run # 构建并允许项目cargo add lib_name # 添加最新版本依赖cargo remove lib_name # 删除依赖cargo update [...
830 words
ABA问题是并发编程中一个经典的问题,尤其在使用无锁数据结构时容易发生。它源于变量值经历了”A→B→A”的变化序列,导致程序逻辑误判状态未改变。以下是详细解析: ABA问题的定义当某个线程执行CAS(Compare-and-Swap)操作时: 线程1读取共享变量的值为A 线程2将值修改为B,随后又改回A 线程1再次检查时发现值仍是A,认为未被修改,继续执行操作 此时程序逻辑可能因中间状态变化而出现错误。 典型案例(链表删除场景)假设一个无锁链表结构: 12345struct Node { int value; Node* next;};Node* head; // 全局头指针 线程1操作: 读取当前头节点指针old_head = head(地址0x1000,值A) 准备将头指针更新为new_head = old_head->next 线程2操作: 删除头节点0x1000,释放内存 新建节点0x2000(值B),插入链表头部 再次删除0x2000,分配新节点0x1000(值C,但地址与旧节点相同)插入头部 结果:线程...
843 words
深入理解无锁队列与C++原子操作引言在多线程编程中,传统的锁机制(如互斥锁)虽然能保证线程安全,但存在性能瓶颈和死锁风险。无锁(Lock-Free)数据结构通过原子操作实现线程安全,能显著提升高并发场景下的性能。本文将详解如何使用C++原子变量实现无锁队列。 原子操作基础什么是原子操作?原子操作是不可分割的最小操作单元,要么完全执行,要么完全不执行。C++11通过<atomic>头文件提供原子类型: 123#include <atomic>std::atomic<int> counter(0); 内存顺序(Memory Order)指定原子操作的内存可见性顺序,常用选项: memory_order_relaxed:无顺序保证 memory_order_acquire:加载操作,保证之后的内存访问不会重排到前面 memory_order_release:存储操作,保证之前的内存访问不会重排到后面 memory_order_seq_cst(默认):严格顺序一致性 12counter.store(42, std::memory_order_r...
932 words
深入解析C++中的静态多态与动态多态多态的本质与价值多态(Polymorphism)作为面向对象编程的三大核心特性之一,是构建灵活、可扩展软件系统的关键所在。在C++中,多态的实现主要分为静态多态(Static Polymorphism)和动态多态(Dynamic Polymorphism)两种形式,它们以不同的方式实现了”一个接口,多种实现”的核心思想。 多态的核心意义 提高代码复用性 增强系统扩展性 降低模块耦合度 实现接口与实现的分离 静态多态:编译时的魔法实现方式函数重载123456class Calculator {public: int add(int a, int b) { return a + b; } double add(double a, double b) { return a + b; } string add(const string& a, const string& b) { return a + b; }}; 运算符重载12345...
985 words
HTTP3.0:QUIC协议详解QUIC是什么QUIC,读作“Quick”,顾名思义就是“快得飞起”。它是Google在2012年推出的一种基于UDP的新型传输协议。UDP大家应该都知道,那个不讲究顺序、不管丢包、不负责重传的“放养型”协议。QUIC就像是给UDP装上了加速器,再加上TCP的一些可靠性,摇身一变成为了一个又快又可靠的传输协议 QUIC为什么这么快QUIC有以下的特点 连接建立快:一见钟情型协议传统的TCP握手需要三次来回(俗称“三次握手”),还得再加个TLS握手才能加密,整个过程就像是在相亲时反复确认“你是谁?”、“你确定是你吗?”、“好吧,那我们开始吧”。而QUIC直接跳过这些繁琐步骤,用一个握手搞定连接和加密,利用缓存,显著减少连接建立时间 拥抱UDP:轻装上阵TCP虽然可靠,但它太重了,总要考虑丢包、顺序、重传等问题。而QUIC基于UDP,轻量级、不啰嗦,改善拥塞控制,拥塞控制从内核空间到用户空间 多路复用:一条路走到黑HTTP/2的多路复用功能是在同一个连接里可以传输多个流(stream)。但TCP有个问题,一旦某个流出问题(比如丢包),整个...