首页 > 其他分享 >以Zed项目为例学习大型Rust项目的组织与管理

以Zed项目为例学习大型Rust项目的组织与管理

时间:2024-08-09 14:39:17浏览次数:11  
标签:Cargo bar Zed 为例 crates project workspace foo Rust

说明

Zed是一款由Atom创始人开发的高性能、协作友好的现代开源代码编辑器,使用Rust编写,集成AI辅助功能,旨在结合传统编辑器的速度和现代IDE的智能特性

Zed项目的组织和管理非常值得学习和研究。下面我将通过我总结后的得出一个精简版例子来说明Zed项目的结构,my_project对应Zed项目的crates文件夹下的zed文件夹

workspace_root/
├── Cargo.toml
└── crates/
    ├── foo/
    │   ├── Cargo.toml
    │   └── src/
    │       └── lib.rs
    ├── bar/
    │   ├── Cargo.toml
    │   └── src/
    │       └── lib.rs
    └── my_project/
        ├── Cargo.toml
        └── src/
            └── main.rs

工作空间根目录的Cargo.toml

[workspace]
members = ["crates/foo", "crates/bar", "crates/my_project"]
default-members = ["crates/my_project"]
resolver = "2"

[workspace.dependencies]
foo = { path = "crates/foo" }
bar = { path = "crates/bar" }
rand = "0.8.5"  # 添加 rand 作为工作空间依赖

[workspace.lints.rust]
unsafe_code = "forbid"
unused_variables = "warn"

[workspace.lints.clippy]
enum_glob_use = "deny"

members字段指定了属于该工作空间的所有 crate(包)

  • 作用:

    • 定义工作空间结构:告诉Cargo哪些项目是这个工作空间的一部分
    • 允许集中管理:可以在工作空间级别管理依赖和构建设置
    • 启用共享编译:成员之间可以共享编译产物,提高构建效率
  • 灵活性:

    • 可以使用相对路径指定成员
    • 支持glob模式,如members = ["crates/*"] 可以包含crates目录下的所有crate

default-members指定了在没有明确指定目标的情况下,默认要构建、测试或运行的工作空间成员(crate)

  • 当你在工作空间根目录运行 cargo build、cargo test 或 cargo run 等命令时,如果没有指定具体的 crate,Cargo 会默认对 default-members 中列出的 crate 执行操作。
  • 在配置中,default-members = ["crates/my_project"] 意味着默认情况下,只有my_project会被构建或运行
  • 设置my_project为默认成员意味着你可以直接在根目录运行cargo run,而不需要指定--package my_project
  • 可以指定多个默认成员,例如:default-members = ["crates/my_project", "crates/foo"]

resolver = "2"在工作空间的Cargo.toml文件中是一个重要的配置项,它指定了Cargo使用的依赖解析器版本

  • 版本

    • "1": 旧版解析器(默认用于2015和2018版本的Rust)
    • "2": 新版解析器(默认用于2021版本的 Rust)

注意到rand指定项目版本信息,这样的好处包括:

  • 在工作空间级别管理依赖版本,确保所有项目使用相同版本的rand
  • 简化了各个项目的Cargo.toml文件,使其更加清晰
  • 方便统一升级所有项目的依赖版本

需要注意的是,这种方式要求所有使用rand的项目都使用相同的版本。如果某个项目需要使用不同版本的rand,你可以在那个项目的Cargo.toml中明确指定版本,覆盖工作空间中定义的版本

例如,如果bar项目需要使用不同版本的rand:

[dependencies]
foo.workspace = true # 也可写成旧版本的Cargo中出现的foo = { workspace = true }
rand = "0.7.3"  # 使用特定版本,而不是工作空间版本

这种配置方式既灵活又统一,非常适合管理包含多个相关项目的工作空间

lint设置用于定义整个工作空间的代码质量和样式规则。好处:

  • 一致性:确保工作空间中所有项目遵循相同的代码规范
  • 安全性:通过禁止不安全代码提高项目的安全性
  • 代码质量:帮助开发者编写更清晰、更高质量的代码
  • 维护性:通过统一的规则,使代码更容易维护和理解

my_project项目

Cargo.toml

[package]
name = "my_project"
version = "0.1.0"
edition = "2021"

[[bin]]
name = "my_project"
path = "src/main.rs"

[dependencies]
foo.workspace = true
bar.workspace = true

[lints]
workspace = true

src/main.rs

use bar::bar_function;
use foo::generate_random_number;

fn main() {
    let num = 10;
    println!("Hello, world! {num} plus one is {}!", bar::add_one(num));
    bar_function();
    let random_number = generate_random_number();
    println!("Random number generated in bar: {}", random_number);
}

foo项目

Cargo.toml

[package]
name = "foo"
version = "0.1.0"
edition = "2021"

[dependencies]
rand.workspace = true

[lints]
workspace = true

[lib]
path = "src/lib.rs"
doctest = false

src/lib.rs

use rand::Rng;

pub fn add(left: u64, right: u64) -> u64 {
    left + right
}

pub fn foo_function() {
    println!("This is a function from foo");
}

pub fn generate_random_number() -> i32 {
    let mut rng = rand::thread_rng();
    rng.gen_range(1..=100)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_works() {
        let result = add(2, 2);
        assert_eq!(result, 4);
    }
}

bar项目

Cargo.toml

[package]
name = "bar"
version = "0.1.0"
edition = "2021"

[lints]
workspace = true

[lib]
path = "src/lib.rs"

[dependencies]
foo.workspace = true

src/lib.rs

use foo::foo_function;

pub fn bar_function() {
    println!("This is a function from bar library");
    foo_function(); // 调用 foo 中的函数
}

pub fn add(left: u64, right: u64) -> u64 {
    left + right
}

pub fn add_one(x: i32) -> i32 {
    x + 1
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_works() {
        let result = add(2, 2);
        assert_eq!(result, 4);
    }
}

bar项目依赖foo项目,调用foo项目的foo_function函数

执行“Cargo run”,项目运行结果如下

Hello, world! 10 plus one is 11!
This is a function from bar library
This is a function from foo
Random number generated in bar: 13

最后,我还给出另一种项目代码组织方式,将my_project项目放到crates文件夹之外的版本,感兴趣的话,详见我的项目仓库

参考

  1. Announcing Rust 1.74.0 | Rust Blog (rust-lang.org)
  2. Workspaces - The Cargo Book (rust-lang.org)

标签:Cargo,bar,Zed,为例,crates,project,workspace,foo,Rust
From: https://www.cnblogs.com/vinciyan/p/18350730

相关文章

  • 在 Rust 中嵌入 Python 来调用外部 Python 库
    我正在尝试学习如何将Python嵌入到Rust应用程序中。出于学习目的,我想创建一个运行永远循环的Rust脚本/应用程序。该循环会休眠设定的时间间隔,醒来后,它使用Pythonrequests库从互联网时间服务器获取当前时间。虽然这不是一个实际应用程序,但我的目标是了解如何从Rust调用......
  • Tool-Docker-以ubuntu:latest为例
    Tool-Docker-以ubuntu:latest为例Ubuntu-Installdockersearchubuntu:查询镜像dockerpullubuntu[:version]:拉取镜像dockerimages:查看镜像dockerps-a:查看当前容器状态dockerrun-itd--namecontainer-nameimages-name[:version]/bin/bash:运行容器dockerexec......
  • Rust——切片
    前言这一章我们一起来学习下切片类型,通过切片,您可以引用集合中连续的元素序列,而不是整个集合。切片是一种引用,因此它没有所有权。内容切片类型这里有一个小的编程问题:编写一个函数,该函数接受一个由空格分隔的单词字符串,并返回它在该字符串中找到的第一个单词。如果函数在字符......
  • 如何把Connection 封装到工具类里面 调用工具类方法实现 增删改查操作 java JDBC
    如何把Connection封装到工具类里面调用工具类方法实现增删改查操作javaJDBC使用数据库连接池以HikariCP为例在JDBC中,使用数据库连接池是一个常见的做法,以提高数据库操作的效率和性能。连接池管理着一组数据库连接,这些连接可以被重用而不是每次需要时都创建新的连接。......
  • 【运维自动化-配置平台】如何使用云资源同步功能(腾讯云为例)
    云资源同步是通过apikey去单向同步云上的主机资源和云区域信息,目前支持腾讯云和亚马逊云。主要特性1、蓝鲸配置平台周期性的单向只读同步云主机和vpc(对应蓝鲸云区域)信息,第一次全量,后面增量2、默认同步到主机池,也可自定义主机池模块,需要手动分配到业务3、主机随云控制台销毁而......
  • Rust_learn_1
    变量与可变性变量声明变量使用let关键字,在默认情况下,变量是不可变的(Immutable)。为此解决该问题,声明变量时在前面加上mut,就可以使变量可变常量常量(constant),在绑定值之后也是不可变的,但是与不可变的变量有很多区别:不可以使用mut,常量永远是不变的声明常量用const关键......
  • docker安装和使用 -- px4-dev-nuttx-focal为例
    安装dockersudoapt-getupdatesudoaptinstalldocker.io镜像源设置1.可scienceInternet开启代理后,还需要设置docker的服务器,参考教程sudomkdir-p/etc/systemd/system/docker.service.dsudovi/etc/systemd/system/docker.service.d/proxy.conf在新建的proxy.co......
  • Java并发—synchronized关键字的应用
    目录1、synchronized适用场景2、synchronized的原理3、synchronized的锁升级4、synchronized的注意事项5、总结synchronized是Java中用于实现线程同步的关键字。它可以在方法级别或代码块级别使用,以确保同一时刻只有一个线程可以访问被同步的代码段。synchronized通......
  • [Rust]使用Rocket框架搭建简单Web服务
    本文主要讲述如何在Rust中使用Rocket搭建简易Web服务1.添加Rocket库Cargo.toml[dependencies]rocket={version="0.5.1",features=["secrets"]}2.创建服务2.1创建一个启动脚本main.rsuserocket::{launch,routes};#[launch]fnrocket()->_{rocket......
  • WebGL拖动控制点绘制贝塞尔曲线——以三次贝塞尔曲线为例
    为了实现该功能,这里将功能分成两部分。第一部分是控制点的拖动功能,第二部分是贝塞尔曲线的绘制功能。控制点的拖动功能:鼠标按下选择点->鼠标移动修改点->鼠标松开释放点。选择点通过发生mousedown事件后遍历控制点数组,判断点击的位置是否和某个点的距离小于一定值,选择第一个满......