在Rust中想要完成一个稍微大一点的项目是不容易的,从JavaScript的角度来讲,不同js文件直接的互相导入是非常宽松且容易的,例如import、export等,甚至可以直接导出已经实例化的成员变量,但据我目前所知,在rust中暂时是不行的,rust只能导出一些类型和函数。
因此需要了解Rust中的项目管理、依赖。
先介绍几个概念:(粗体为原文,其余为我的理解)
Cargo.toml
文件,阐述如何去构建这些 crate。use
关键字允许你控制作用域和路径的私有性。package > crate > module
。一个二进制crate,它的充分必要条件是会有./src/main.rs
这个文件,是整个用于执行crate的入口文件。
一个library crate,在某些翻译中也称为库crate或库,明显是翻译问题,及不准确。library crate的充分必要条件是有./src/lib.rs
这个文件。
对于一个package来说,要满足以下的条件:
回忆一下,如何新建一个项目,我会使用cargo new
命令,这个命令会在当前目录下自动创建一个binary application,因为会自动生成./src/main.rs
。
假设我们执行cargo new my-project
。
在此,我们有了一个只包含 src/main.rs
的包,意味着它只含有一个名为 my-project 的binary crate。如果一个包同时含有 src/main.rs
和 src/lib.rs
,则它有两个 crate:一个binary和一个library的,且名字都与包相同。
除此之外,可以通过将文件放在 src/bin
目录下,一个包可以拥有多个binary crate:每个 src/bin
下的文件都会被编译成一个独立的binary crate。
详细信息见该链接:https://kaisery.github.io/trpl-zh-cn/ch07-01-packages-and-crates.html。
在我之前学习的http-server项目中,http crate的目录结构是这样的:
可以看出这是一个library crate,在编写httprequest和httpresponse文件的代码时,我发现没有代码提示,后来我才知道,对于这种项目,在lib.rs中通过以下代码可以直接声明其他rs文件中的内容是一个mod:
pub mod httprequest;
pub mod httpresponse;
这也是lib.rs文件中唯一的两行代码,只要先在lib.rs中声明这两行代码,编译器就会任务这两个文件是个根目录形成树形结构的,这时就有代码提示了。
更详细的内容见该链接:https://www.tutorialspoint.com/rust/rust_modules.htm。
假设现在目录下只有一个rary.rs文件,使用以下命令编译该文件:
// rary.rs
pub fn public_function() {
println!("called rary's `public_function()`");
}
fn private_function() {
println!("called rary's `private_function()`");
}
pub fn indirect_access() {
print!("called rary's `indirect_access()`, that\n> ");
private_function();
}
rustc --crate-type=lib rary.rs
就会生成一个library.rilb
文件,然后创建一个main.rs文件
// extern crate rary; // May be required for Rust 2015 edition or earlier 在2015版本之前需要这句话
fn main() {
rary::public_function();
// Error! `private_function` is private
//rary::private_function();
rary::indirect_access();
}
然后用以下命令编译:
rustc main.rs --extern rary=library.rlib --edition=2018
就可以生成 main.exe 文件,然后通过./main
来执行main.exe这个文件。
详细内容见该链接https://doc.rust-lang.org/rust-by-example/crates/lib.html。
在之前的工作前构建了一个包含bin crate 和lib crate 的包。你可能会发现,随着项目开发的深入,lib crate 持续增大,而你希望将其进一步拆分成多个lib crate。对于这种情况,Cargo 提供了一个叫 工作空间(workspaces)的功能,它可以帮助我们管理多个相关的协同开发的pkg。
有了workspace之后,关系是这样的:
workspace > pkg > crate > mod
先创建一个文件夹作为工作空间,然后创建Cargo.toml作为配置文件:
[workspace]
members = ["tcpserver", "tcpclient", "httpserver", "http"]
这四个成员分别作为4个pkg,前两者是测试tcp连接的,后两者是构造http服务器的源文件,这4个包公用一个Cargo.lock。
运行时可以使用命令 cargo run -p
来运行指定的pkg。cargo test同理。
还是刚才的例子,http是一个lib crate,现在创建了一个bin crate名为httpserver。在Cargo.toml的[dependencies]中要表明http crate,即使这个crate是自己写的。
[package]
name = "httpserver"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
http = {path = "../http"}
serde = {version="1.0.136", features=["derive"]}
serde_json = "1.0.79"
详细内容见该链接https://kaisery.github.io/trpl-zh-cn/ch14-03-cargo-workspaces.html。