Rust工具的秘密

最近抽时间看完了<<The secrets of Rust tools» 一书, 以下简称tools. Tools这边书属于入门级别的rust书籍, 一个周末, 每天看3到4个小时可以看完. 整本书分为了好几个小的项目, 每个项目的模式是一样的TDD. 项目 count lines (wc -l) 提到了 BufRead trait用来做入参, 使用collect 把lines() Vec<Result<» 收集为 Result<Vec<» 简单介绍了 anyhow:Result, bail, context等常见用法, 介绍了 assert_cmd crate直接测试 cargo 命令行crate, 简单介绍了clap解析flag等命令行参数, 以及在后面的章节介绍了clap开发 cargo plugin, logbook (clap, serde) 简单介绍了File的io操作, 以及File open option builder 模式, 介绍了AsRef<Path>参数,方便测试, 如何public lib crate, 介绍Path to PathBuf the From trait, 以及as_ref From AsRef to reference, 使用serde 和serde_json序列化从硬盘读写数据,保持数据 回顾clap 的用法 weather client (reqwest) 简单介绍reqwest blocking模式, ...

March 28, 2025 · datewu

Dijkstra算法实现

Dijkstra算法是一种图遍历算法,用于找到源顶点到图中所有其他顶点的最短路径。 数据结构 顶点(Vertex): 一个保存顶点id的结构体。 边(Edge): 一个保存起点和终点顶点id的结构体,以及边的权重(代价),必须是正整数。 图(Graph): 一个保存所有顶点和边的结构体。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 use std::cmp::Ordering; #[derive(Debug, PartialEq, Eq, Clone, Hash)] pub struct Vertex { // `id`: 顶点的唯一标识符,用字符串表示。 id: String, } #[derive(Debug, PartialEq, Eq, Clone)] pub struct Edge { // `from`: 边的起点顶点id。 from: String, // `to`: 边的终点顶点id。 to: String, // `cost`: 遍历该边的权重或代价。 cost: u32, } #[derive(Debug, PartialEq, Eq)] pub struct Graph { // `vertices`: 一个包含所有顶点的`Vertex`结构体向量。 vertices: Vec<Vertex>, // `edges`: 一个包含所有边的`Edge`结构体向量。 edges: Vec<Edge>, } #[derive(Clone, Eq, PartialEq)] struct Node { // `cost`: 从源顶点到该顶点的当前最短距离。 cost: u32, // `vertex_id`: 该节点所代表顶点的id。 vertex_id: String, } // 为`Node`实现`Ord`特性,使其可用于`BinaryHeap`。 impl Ord for Node { fn cmp(&self, other: &Self) -> Ordering { // 反转`cost`的排序,使`BinaryHeap`表现为最小堆。 // Rust中的`BinaryHeap`默认是最大堆,反转比较结果会使其成为最小堆。 other.cost.cmp(&self.cost) } } // 为`Node`实现`PartialOrd`特性。 impl PartialOrd for Node { fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) } } Dijkstra算法 最低代价 将源顶点到自身的距离初始化为0。 将源顶点及代价0推入优先队列。 循环直到优先队列为空。 从优先队列中弹出距离最小的顶点。 如果当前顶点是目标顶点,则跳出循环。 如果已经找到了更短的路径到达当前顶点,则跳过。 遍历所有以当前顶点为起点的边。 计算通过当前顶点到达邻居顶点的代价。 如果找到了更短的路径到达邻居顶点,则更新距离,并将其推入优先队列。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 use std::collections::{BinaryHeap, HashMap}; impl Graph { // 使用Dijkstra算法计算从src到dest的最低代价。 pub fn dijkstra_cost(&self, src: &str, dest: &str) -> Option<u32> { // `distances`: 一个`HashMap`用于存储从源顶点到每个顶点的最短距离。 let mut distances: HashMap<String, u32> = HashMap::new(); // `pq`: 一个`BinaryHeap`(优先队列)用于高效选择距离最小的顶点。 let mut pq: BinaryHeap<Node> = BinaryHeap::new(); // 将源顶点到自身的距离初始化为0。 distances.insert(src.to_string(), 0); // 将源顶点及代价0推入优先队列。 pq.push(Node { cost: 0, vertex_id: src.to_string(), }); // 循环直到优先队列为空。 while let Some(Node { cost, vertex_id }) = pq.pop() { // 如果当前顶点是目标顶点,则返回代价。 if vertex_id == dest { return Some(cost); } // 如果已经找到了更短的路径到达当前顶点,则跳过。 if cost > *distances.get(&vertex_id).unwrap_or(&u32::MAX) { continue; } // 遍历所有以当前顶点为起点的边。 for edge in self.edges.iter().filter(|e| e.from == vertex_id) { // 计算通过当前顶点到达邻居顶点的代价。 let next_cost = cost + edge.cost; // 如果找到了更短的路径到达邻居顶点,则更新距离,并将其推入优先队列。 if next_cost < *distances.get(&edge.to).unwrap_or(&u32::MAX) { distances.insert(edge.to.clone(), next_cost); pq.push(Node { cost: next_cost, vertex_id: edge.to.clone(), }); } } } // 如果没有找到路径,则返回None。 None } } 最短路径 与最低代价的算法大致相同,但需要保存一个previous的HashMap来存储到达每个顶点的最短路径上的前一个顶点。 ...

March 11, 2025 · datewu

Kafka 快速入门

什么是 Kafka Kafka 是一个分布式流处理平台。 可以将其视为一个高吞吐量、容错的消息队列。 它专为处理实时数据流而设计。 概念 主题(Topic): 发布记录的类别或馈送名称。 分区(Partition): 一个主题被分成多个分区,这些分区是有序的、不可变的记录序列。分区实现了并行性和可伸缩性。 生产者(Producer): 将记录发布到 Kafka 主题的应用程序。 消费者(Consumer): 订阅一个或多个主题并处理记录的应用程序。 代理(Broker): Kafka 服务器。代理存储数据。 集群(Cluster): 一起工作的代理组。 副本(Replica): 每个分区可以跨多个代理进行复制,以实现容错。 领导者(Leader): 分区的一个副本被指定为领导者,处理所有读写请求。 追随者(Follower): 分区的其他副本是追随者,从领导者复制数据。 偏移量(Offset): 分配给分区内每个记录的唯一、顺序 ID。消费者使用偏移量跟踪它们在分区中的位置。 消费者组(Consumer Group): 一组消费者一起从一个主题消费记录。每个分区被分配给一个组内的一个消费者。 保留策略(Retention Policy): 定义 Kafka 在删除记录之前保留记录的时间。 ZooKeeper: 用于管理和协调 Kafka 集群(尽管较新版本正在摆脱 ZooKeeper)。 常见应用场景 实时数据管道: 从各种来源摄取和处理数据流。 日志聚合: 将来自多个服务器的日志收集到一个中心位置。 流处理: 构建分析和响应数据流的实时应用程序。 事件溯源: 存储表示应用程序状态更改的事件序列。 消息传递: 应用程序之间可靠、高吞吐量的消息传递。 活动跟踪: 实时跟踪网站或应用程序上的用户活动。 提交日志: 用作分布式数据库的提交日志。 Kafka 在系统设计中的作用 解耦: Kafka 解耦了生产者和消费者,允许它们独立发展。 可伸缩性: Kafka 可以处理大量数据,并通过添加更多代理进行水平扩展。 可靠性: 容错确保数据不会丢失。 缓冲: ...

March 10, 2025 · datewu

Mermaid图表工具

创建Mermaid初始化的局部视图 在你的 layouts/partials 目录下创建一个名为 mermaid-init.html 的新文件。 将以下代码添加到 mermaid-init.html 中: 1 2 3 4 <script type="module"> import mermaid from '/js/mermaid.esm.min.mjs'; mermaid.initialize({ startOnLoad: true }); </script> 添加shortcodes 新建 layouts/shortcodes/mermaid.html 文件. 将以下代码添加到 mermaid.html 中: 1 2 3 4 5 6 7 8 9 10 11 12 13 {{- $scratch := .Page.Scratch -}} {{- if not ($scratch.Get "mermaid-counter") -}} {{- $scratch.Set "mermaid-counter" 1 -}} {{- partial "mermaid-init.html" . -}} {{- else -}} {{- $scratch.Add "mermaid-counter" 1 -}} {{- end -}} {{- $id := printf "mermaid-%d" ($scratch.Get "mermaid-counter") -}} <div id="{{ $id }}"> <pre class="mermaid"> {{- .Inner | safeHTML }} </pre> </div> 说明: ...

March 9, 2025 · datewu

遍历二叉搜索树

二叉搜索树(BST) 数据结构: 左子树节点的值都小于根节点的值 右子树节点的值都大于根节点的值 左右子树也分别为二叉搜索树 空节点为二叉搜索树 插入操作: 找到合适的位置, 小于当前节点插左树,大于等于当前节点插右树,空树直接插入, 保持二叉搜索树的性质, 重复1-3 基于Box<T>的二叉搜索树的实现 数据结构和Insert方法: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 // Maybe I should use a reference count instead of a box pointer // for the bfs method. #[derive(Debug, PartialEq, Eq, Clone)] pub struct BinarySearchBoxNode { val: i32, left: Option<Box<Self>>, right: Option<Box<Self>>, } impl BinarySearchBoxNode { fn new(val: i32) -> Self { Self { val, left: None, right: None, } } fn insert(&mut self, val: i32) { if val < self.val { if let Some(left) = &mut self.left { left.insert(val); } else { self.left = Some(Box::new(Self::new(val))); } return; } if let Some(right) = &mut self.right { right.insert(val); } else { self.right = Some(Box::new(Self::new(val))); } } } BFS vs DFS 主要区别: ...

March 9, 2025 · datewu

归并排序和快排

归并排序 归并排序的步骤 递归地把当前序列拆分为两个子序列,直到每个子序列只有一个元素 对每个子序列递归地调用归并排序 将两个有序子序列合并成一个最终的有序序列 重复步骤1~3,直到排序完成 归并排序的步骤实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 pub fn merge_sort(data: &mut [i32]) { // base case if data.len() <= 1 { return; } let mid = data.len() / 2; // recusive call two sub array merge_sort(&mut data[0..mid]); merge_sort(&mut data[mid..]); // merge the two sorted sub array; merge(data, 0, mid, data.len()); } fn merge(data: &mut [i32], low: usize, mid: usize, high: usize) { // copy left and right sub array let left = &data[low..mid].to_vec(); let right = &data[mid..high].to_vec(); // keep two pointer to two sub array let mut i = 0; let mut j = 0; // the merged array index let mut k = low; // the merge loop, increasing k from low to high; while k >= low && k < high { // assign the smaller value to data[k] while i < left.len() && j < right.len() { if left[i] <= right[j] { data[k] = left[i]; i += 1; } else { data[k] = right[j]; j += 1; } k += 1; } // assign the rest value of left part to data[k..] while i < left.len() { data[k] = left[i]; i += 1; k += 1; } // assign the rest value of right part to data[k..] while j < right.len() { data[k] = right[j]; j += 1; k += 1; } } } 快速排序 ...

March 8, 2025 · datewu

WireGuard VPN 无法访问github

为什么 GitHub 不喜欢我的 MTU 让我来告诉你我花了一整天与我的 WireGuard VPN 搏斗的挫败经历, 以及为什么 GitHub 成了唯一一个不配合的网站。我希望我的经验, 特别是如果你像我一样在 microk8s 环境中运行 WireGuard,能帮你省去一些麻烦。 环境:microk8s、Ubuntu 和 WireGuard 我的环境有点复杂。 我有一个运行在 Ubuntu 24.04.2 LTS 服务器节点(GNU/Linux 6.8.0-54-generic x86_64)上的 microk8s 集群。 我将我的 WireGuard VPN 服务器作为 pod 在这个 microk8s 集群中运行。这增加了一层我最初没有考虑到的网络复杂性。 问题:GitHub 无法访问(但其他一切都很好) 一切似乎都很好。我可以通过我的 WireGuard VPN 访问大多数网站。 Google、YouTube、Twitter——都没问题。但是 https://github.com 就是无法加载。 curl https://github.com 无限期地挂起。我挠着头,想知道是 DNS 问题、防火墙问题,还是其他什么问题。 调试:深入网络 初始测试: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 curl github.com # 有效!返回 301 重定向到 HTTPS curl -v github.com * Host github.com:80 was resolved. * IPv4: 20.27.177.113 * Trying 20.27.177.113:80... * Connected to github.com (20.27.177.113) port 80 > GET / HTTP/1.1 > Host: github.com > User-Agent: curl/8.5.0 > Accept: */* > < HTTP/1.1 301 Moved Permanently < Content-Length: 0 < Location: [https://github.com/](https://github.com/) < * Connection #0 to host github.com left intact curl [https://github.com](https://github.com) # 挂起... 这令人难以置信地困惑。HTTP 有效,但 HTTPS 无效。 但是 Google 和 Twitter 等其他 HTTPS 网站都很好。这表明问题特定于 HTTPS,并且可能与 GitHub 有关。 ...

March 4, 2025 · datewu

黑胶唱片Rails,能抗能打

今天在Hacker New上看到了一篇称赞Raisl的文章Why Rails Still Matters。 原文用黑胶唱片做为引子,说明以rails为代表的老旧web技术是ok的,不比 新的Next.js之类差很多,大家的应用场景不同而已. 个人顾个人的场子,井水不犯河水就好. 我的想法 我是从Rails入行的软件开发,入职了在一个很小的微型企业. 从Rails开始,我慢慢接触并且使用了Vim, Linux, Ruby, ORM, SQL, Postgresql, Python(在大学只是理论学习), Lua, Javascript, CSS, Markdown, Docker, Go, Kubernetes, Rust等等各种各样的技术. 可以说Rails是我从事IT行业的引路人. 最后从事和Ruby相关的工作是2016年的时候,负责给一个稍微大一点的 初创公司运维那些web服务器,数据库之类的. 时间过得很快,我很久没接触Rails或者Ruby了. 记不清是哪一个时间段,我非常喜欢静态强类型的编程语言. 估计是被Ruby的 method call chian链路搞烦了,也可能是被class搞烦了. 现在我也不喜欢Python的class 和所有的oop编程语言(java为代表, C++也不喜欢). web/http 整个web开发说白了基本上是面向浏览器开发,包含前后端技术. 前端不多多说,html/css/javascript三个加起来本质上就是浏览器的DSL. 最新的wasm稍微可以说自己脱离了浏览器的控制,但也没脱离多少. Node.js/deno也不敢完全说自己和浏览器没少关系 后端方面,屁股决定脑袋,也受到了浏览器不小的制约,看看Nginx和Header相关配置有多少就知道我在说什么了. HTTP协议这么多年了,也是受到浏览器的控制的,毕竟协议谁都可以写. 市场支持不支持,支持的多不多,是和协议本身的各项指标关系不大的. 浏览器本身是一个很复杂而软件,复杂程度不输操作系统. 越是靠近用户层就越复杂,因为用户/人类是变数最多的. 相反,越靠近物理硬件,软件就可以设计的越简单. 比如网络传输的物理层,网络层,传输层,是一层复杂过一层,一层包一层, 像俄罗斯套娃一样. 操作系统,管好4大件,处理好中断,调度就好了. 浏览器光是html的渲染(想象一下一个动态的window size)就够复杂了, 别提那些音/视频API、网络请求、安全策略了 Gemini 最后用gemini总结一下这篇文章,并介绍一下Rails和Next.js的背景,以及现在的web开发趋势。 我基本认同gmini的说法。 文章主要思想 这篇文章的核心观点是,虽然像Next.js这样的新兴前端框架提供了更高级的功能和更精美的界面,但Ruby on Rails仍然是一个有价值的web开发工具,尤其是在注重简单性、开发速度和可维护性的项目上。作者认为,现代JavaScript框架的复杂性实际上会增加开发难度,而Rails的抽象和对web基础的关注使其成为许多应用程序的强大选择,即使在AI和动态web体验的时代也是如此。他用黑胶唱片类比,说明了为什么旧技术在新的创新出现后仍然存在并有价值。本质上,这篇文章推崇Rails是一种实用、高效且具有成本效益的解决方案,即使它不是“最新潮”的技术。 Rails 和 Next.js 的背景 Ruby on Rails (Rails):是一个基于Ruby语言的web应用开发框架。它由David Heinemeier Hansson于2003年创建,旨在提高开发效率和简化web应用开发过程。Rails遵循“约定优于配置”的原则,提供了一系列工具和约定,帮助开发者快速构建功能丰富的web应用。它在过去二十年中一直是流行的后端框架,许多知名公司如Airbnb、Shopify、Github等都使用Rails构建。 ...

February 22, 2025 · datewu

新项目用rust, 新代码也用rust

今天在Hacker New上看到了一篇称赞rust的文章Writing New Code in Rust Is a Win for All of Us。 原文内容就不贴出来了,maillist的内容一般都可以活的很久,随时可以去阅读。 虽然我很喜欢rust, 甚至从golang转了rust开发。 但是我没有过任何内核开发的经验,而且具体到C/C++语言我也只有大学的理论,没有实际的工作经验。 我只是一个一般的linux用户,和内核的交集只有内核升级以及编译裁剪内核,所以我没有和这篇文章产生强烈共鸣。 Gemini 我使用gemini总结了一下,存挡,看什么时候能和这篇文章共鸣。 这封邮件来自 rust-for-linux 邮件列表,讨论了在 Linux 内核中使用 Rust 语言的可能性。 Greg KH (Greg Kroah-Hartman) 是一位著名的 Linux 内核开发者和维护者。 他以在 staging 子系统、USB 子系统和驱动核心方面的工作而闻名。 他是内核社区中非常有影响力的人物,也是稳定内核版本的维护者。他的意见非常重要。 在这封邮件中,他强烈主张在新内核代码/驱动程序中采用 Rust 语言。 他指出,Rust 可以防止常见的 C 语言错误,例如内存覆盖、释放后使用错误以及错误处理问题。 他认为,使用 Rust 编写新代码将使开发人员能够专注于更复杂的错误,并创建更安全、更强大的 API。 Boqun Feng: 一位内核开发人员,他发起了这个特定的讨论主题,他对 Rust 内核策略提出了担忧。 他最初的电子邮件(未显示)可能质疑了采用 Rust 的明智性或可行性。 H. Peter Anvin (hpa): 另一位长期从事内核开发的开发人员,以其在 x86 架构和启动过程方面的工作而闻名。 他参与了关于底层内核细节的讨论。在显示的片段中,他提出 C++ 可能比 Rust 更渐进的方法,因为它可能更直接地改进现有的 C 代码。 Miguel Ojeda: 他似乎是 Rust for Linux 项目中最活跃的开发人员之一。他很可能完成了 Rust 绑定的很多工作。 Christoph Hellwig: 一位以其在存储和内存管理方面的工作而闻名的内核开发人员。他参与了关于性能和核心内核基础设施的讨论。 邮件还强调: 不断努力改进现有 C 代码的重要性。 Rust 在改进 API 设计和安全性方面的潜力。 开发人员为 Rust 集成做出贡献的意愿。 总的来说,这封邮件提出了一个令人信服的理由, 说明为什么应该在 Linux 内核中采用 Rust,强调了它在提高代码质量、安全性和可维护性方面的潜力。Greg KH 的支持是这次讨论中的一个重要因素。 ...

February 21, 2025 · datewu

2024年终总结

大雪 年初武汉下了好大好大的雪。还有人去江滩那里拿个硬纸板滑雪呢。 俗话说瑞雪兆丰年,2024年,我倒是没走啥好运。平静且孤独吧。 下完雪后的,3, 4月分,去踏了踏春:看樱花, 爬龟山,光谷马戏团。。。 PC 十一年前2013年我DIY了自己的第一台台式机,今年2024年DIY了第二台电脑。 每次都是因为笔记本性能跟不上了。 2011年的华硕笔记本,并没有坚如磐石。2018年的macbook pro能用,但是电池出了问题。 新的PC装了一段时间的windows 11, 玩了一个快两个月的英雄联盟,觉得没意思。就换成了Ubuntu 2024.04, 一直用到现在,蛮好用的。 而且微信和QQ也都出了Linux版本的,不耽误事情。当然,微信是今年下半年才支持的Linux。 我估计是国产操作系统倒逼的鹅厂,现在好些国企/事业单位都只能采购国产的cpu,国产的操作系统了,虽然很难用,但是行政力量大于天。 驾校 在武汉考驾照,大家还是多花点钱吧,省心,不遭罪。 具体的坑我可能会单独写一篇文章,在这里就只简单的说下: 整个科目三考过来,给大家一条建议吧,想快速拿证(没时间练车)的,多打点下。有时间的,对自己技术信的过的,建议做好心里准备,一定是大于等于4次才会过。 另外,我科目二也是考了五次,也是没有打点过任何东西。 回想起来除了花了400快打学时外,就是花时间和花补考费了。 工作 2024年,一整年,只面试了一场,还是年末高峰期的一场面试。投的简历应该只有四五十份吧。 年初没啥Rust的岗位投,没的投,之后,有岗位了但大多是Web 3的岗位。没意思。 另外,上家公司一直到6月份,我签了丧权辱国的保密协议后才给了我离职证明,也不方便我找工作。 做了一年的Upper, 投了的56个视频,收获了60个粉丝,还不错。 微信视频号上,发些英语学习的视频,有120个粉丝,但是被限流量了,我就不去更新视频号了。 限流也很搞笑,刚刚花90块钱,用所谓的“加热工具”加热了下视频,结果号爆炸了。 我觉得他们应该先提醒我,而不是等我花了钱再说不行,然后也不退钱。 新年寄语 新的一年2025年马上就要来了。我又开始写博客了,这是一个好的开始。 新的一年,我希望自己,好好学习,好好生活,家人身体健康。 能个远程的工作,做做奶爸,最好了。 加油!

December 30, 2024 · datewu