Packages和Crates
Crates本意是木箱,在Rust里面用于表示二进制仓库,意思就是编译后的一个可以被其他人使用的可执行的crate,或仓库crate。因为木箱嘛,就是装了东西可以搬来搬去的。
Packages就是我自己创建的一个项目,它可以包含一个或多个Crates,用一个Cargo.toml
文件进行管理,来描述那些crates该怎么构建。
在Rust中,你创建的package可以有多个Crates,但不不能一个crate都没有。当使用cargo new my-project
命令创建一个项目的时候,这就是你的一个package,其中的src/main.rs
,就是一个和package同名的可执行crate(binary crate),在Cargo.toml
中并没有提及,因为Rust默认src/main.rs
就是入口,也就是所谓的这个crate的根所在。
如果在src目录下的不是main.rs,而是lib.rs,那这就是一个库crate(library crate)。
如果src目录下既有main.rs,又有lib.rs,那就会编译出一个可执行crate,以及一个仓库crate,这两个crates都和package同名。而且,一个package里面也可以有多个可执行crates。那就是在src/bin
下面,建多个rs文件,每一个都会编译为和文件名同名的可执行crates。
模块(Modules)
模块用于组织我们写的代码,以及控制访问权限。现在举个例子,假设现在有一家餐馆,餐馆分成前台和后台,前台就是客人待着的地方,服务员给客人安排座位,以及点菜。后台就是厨师做菜,洗盘子,管理人员做餐馆管理事项的地方。我们安装前台来组织模块。
首先我们创建仓库crate:
cargo new --lib restaurant
然后在src/lib.rs
中写如下代码:
mod front_of_house {
mod hosting {
fn add_to_waitlist() {}
fn seat_at_table() {}
}
mod serving {
fn take_order() {}
fn serve_order() {}
fn take_payment() {}
}
}
这组织方式有点像目录,看一下结构:
crate
└── front_of_house
├── hosting
│ ├── add_to_waitlist
│ └── seat_at_table
└── serving
├── take_order
├── serve_order
└── take_payment
模块的访问
模块不仅仅是组织代码结构,还有访问管理的作用,比如下面这段代码:
mod front_of_house {
mod hosting {
fn add_to_waitlist() {}
}
}
pub fn eat_at_restaurant() {
// Absolute path
crate::front_of_house::hosting::add_to_waitlist();
// Relative path
front_of_house::hosting::add_to_waitlist();
}
这段代码在eat_at_restaurant中,通过绝对路径和相对路径访问了模块中的add_to_waitlist方法,首先,这说明了模块中元素的方式,绝对路径是用crate开头,用
::
进行访问,相对路径就是直接从你当前所在的模块名称开始。
但是这段代码会出现编译错误:
$ cargo build
Compiling restaurant v0.1.0 (file:///projects/restaurant)
error[E0603]: module `hosting` is private
--> src/lib.rs:9:28
|
9 | crate::front_of_house::hosting::add_to_waitlist();
| ^^^^^^^ private module
|
note: the module `hosting` is defined here
--> src/lib.rs:2:5
|
2 | mod hosting {
| ^^^^^^^^^^^
error[E0603]: module `hosting` is private
--> src/lib.rs:12:21
|
12 | front_of_house::hosting::add_to_waitlist();
| ^^^^^^^ private module
|
note: the module `hosting` is defined here
--> src/lib.rs:2:5
|
2 | mod hosting {
| ^^^^^^^^^^^
这个提示明确指出了你访问的hosting模块,是一个私有模块,不能直接访问。也就是说,除非你是在front_of_house这个模块里面来调用hosting模块,否则是不能访问的。除非hosting模块是公有的,在前面加一个pub
关键字。包括add_to_waitlist方法,也是私有的,需要对外开放,也是需要pub
关键字的:
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
pub fn eat_at_restaurant() {
// Absolute path
crate::front_of_house::hosting::add_to_waitlist();
// Relative path
front_of_house::hosting::add_to_waitlist();
}
如果在某个mod里面的一个函数,需要访问所在mod外面的函数,可以使用super作为相对路径:
fn serve_order() {}
mod back_of_house {
fn fix_incorrect_order() {
cook_order();
super::serve_order();
}
fn cook_order() {}
}
下面看两个例子,说明下在mod中定义struct和枚举,并访问:
mod back_of_house {
pub struct Breakfast {
pub toast: String,
seasonal_fruit: String,
}
impl Breakfast {
pub fn summer(toast: &str) -> Breakfast {
Breakfast {
toast: String::from(toast),
seasonal_fruit: String::from("peaches"),
}
}
}
}
pub fn eat_at_restaurant() {
// Order a breakfast in the summer with Rye toast
let mut meal = back_of_house::Breakfast::summer("Rye");
// Change our mind about what bread we'd like
meal.toast = String::from("Wheat");
println!("I'd like {} toast please", meal.toast);
// The next line won't compile if we uncomment it; we're not allowed
// to see or modify the seasonal fruit that comes with the meal
// meal.seasonal_fruit = String::from("blueberries");
}
下面是枚举类型:
mod back_of_house {
pub enum Appetizer {
Soup,
Salad,
}
}
pub fn eat_at_restaurant() {
let order1 = back_of_house::Appetizer::Soup;
let order2 = back_of_house::Appetizer::Salad;
}
使用use
来访问模块
use
有点类似python、java里面的import,根C#的use一样,看例子:
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
hosting::add_to_waitlist();
hosting::add_to_waitlist();
}
这个use是绝对路径的写法,也可以使用相对路径:
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
use self::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
hosting::add_to_waitlist();
hosting::add_to_waitlist();
}
和其他语言一样,use进来的还能改名,使用as
关键字:
use std::fmt::Result;
use std::io::Result as IoResult;
fn function1() -> Result {
// --snip--
}
fn function2() -> IoResult<()> {
// --snip--
}
另外,use前面还可以用pub进行修饰,这样外部代码也可以使用这个命名,类似这样:
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
pub use crate::front_of_house::hosting;
如果有别的文件里面引用到了这个文件,也可以直接使用hosting。
如果有如下的引用:
// --snip--
use std::cmp::Ordering;
use std::io;
// --snip--
可以简写成这样:
// --snip--
use std::{cmp::Ordering, io};
//
还有:
use std::io;
use std::io::Write;
可以简写成:
use std::io::{self, Write};
还有通配符可以使用:
use std::collections::*;
用不同的文件来组织模块
随着模块的增加,都写在一个文件里也不好管理,比如上面那个front_of_house模块,可以在src下创建一个同名的文件,叫front_of_house.rs
,里面内容就是:
pub mod hosting {
pub fn add_to_waitlist() {}
}
然后在src下的lib.rs或者main.rs里面可以写:
mod front_of_house;
pub use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
hosting::add_to_waitlist();
hosting::add_to_waitlist();
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 jimmyseraph@testops.vip