包(package)
默认创建一个二进制package,package
其实就是一个项目,是cargo
的一个功能,允许我们创建,测试和分享crate
➜ rust cargo new hello_rust
Creating binary (application) `hello_rust` package
note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
➜ rust cd hello_rust
➜ hello_rust git:(master) ✗ tree
.
├── Cargo.toml
└── src
└── main.rs
1 directory, 2 files
➜ hello_rust git:(master) ✗
小结:
- 我们通过
cargo
创建的hello_rust
就是一个二进制package
- 输出Creating
binary (application)
hello_rust package - 约定俗成:
cargo
的惯例是以src/main.rs
作为二进制包的根文件,也即作为程序的入口。该文件编译之后的名字和我们创建的package名字相同,也为hello_rust
,所有的代码都是从该文件的main
函数开始执行
可执行package
编译并运行:
➜ hello_rust git:(master) ✗ cargo run
Compiling hello_rust v0.1.0 (/Users/liukunlong/rust/hello_rust)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.85s
Running `target/debug/hello_rust`
Hello, world!
➜ hello_rust git:(master) ✗
查看编译后的目录结构:
- 会看到有一个名为
hello_rust
的二进制文件 - 直接运行它,也会直接输出
hello, world
➜ hello_rust git:(master) ✗ tree
.
├── Cargo.lock
├── Cargo.toml
├── src
│ └── main.rs
└── target
├── CACHEDIR.TAG
└── debug
├── build
├── deps
│ ├── hello_rust-47671166f4c95115
│ ├── hello_rust-47671166f4c95115.0wekr9jbnot8e5m7k1zy6am5l.rcgu.o
│ ├── hello_rust-47671166f4c95115.5bnqosv9dxgdsdvjuoirftlt6.rcgu.o
│ ├── hello_rust-47671166f4c95115.5s7u4chpxl2hsjkqizh33o3et.rcgu.o
│ ├── hello_rust-47671166f4c95115.7f9y7pvlcp57vkocwa494mxv4.rcgu.o
│ ├── hello_rust-47671166f4c95115.byzvs0pkajy0ewugsiwdw4e8w.rcgu.o
│ ├── hello_rust-47671166f4c95115.d
│ └── hello_rust-47671166f4c95115.de52o0skguo6qnp0eo10uvgp1.rcgu.o
├── examples
├── hello_rust
├── hello_rust.d
└── incremental
└── hello_rust-275zygvnlq6ng
├── s-gzqwa8ndyk-1274bf2-1z8u6kagyer666gu5h78mrm7n
│ ├── 0wekr9jbnot8e5m7k1zy6am5l.o
│ ├── 5bnqosv9dxgdsdvjuoirftlt6.o
│ ├── 5s7u4chpxl2hsjkqizh33o3et.o
│ ├── 7f9y7pvlcp57vkocwa494mxv4.o
│ ├── byzvs0pkajy0ewugsiwdw4e8w.o
│ ├── de52o0skguo6qnp0eo10uvgp1.o
│ ├── dep-graph.bin
│ ├── query-cache.bin
│ └── work-products.bin
└── s-gzqwa8ndyk-1274bf2.lock
9 directories, 24 files
➜ hello_rust git:(master) ✗ cd target/debug
➜ debug git:(master) ✗ ll
total 920
drwxr-xr-x 2 bytedance staff 64B 9 8 22:31 build
drwxr-xr-x 10 bytedance staff 320B 9 8 22:31 deps
drwxr-xr-x 2 bytedance staff 64B 9 8 22:31 examples
-rwxr-xr-x 1 bytedance staff 454K 9 8 22:31 hello_rust
-rw-r--r-- 1 bytedance staff 105B 9 8 22:31 hello_rust.d
drwxr-xr-x 3 bytedance staff 96B 9 8 22:31 incremental
➜ debug git:(master) ✗ ./hello_rust
Hello, world!
➜ debug git:(master) ✗
库package
创建一个库package
➜ rust cargo new lib_rust --lib
Creating library `lib_rust` package
note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
➜ rust cd lib_rust
➜ lib_rust git:(master) ✗ tree
.
├── Cargo.toml
└── src
└── lib.rs
1 directory, 2 files
➜ lib_rust git:(master) ✗ cargo run
error: a bin target must be available for `cargo run`
➜ lib_rust git:(master) ✗ cargo build
Compiling lib_rust v0.1.0 (/Users/liukunlong/rust/lib_rust)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.36s
➜ lib_rust git:(master) ✗ tree
.
├── Cargo.lock
├── Cargo.toml
├── src
│ └── lib.rs
└── target
├── CACHEDIR.TAG
└── debug
├── build
├── deps
│ ├── lib_rust-1b5c3fee316f2a85.1ewmc71fglnteipcah3q7t2tb.rcgu.o
│ ├── lib_rust-1b5c3fee316f2a85.d
│ ├── liblib_rust-1b5c3fee316f2a85.rlib
│ └── liblib_rust-1b5c3fee316f2a85.rmeta
├── examples
├── incremental
│ └── lib_rust-1yrg9bmycp8cm
│ ├── s-gzqx1i1ou2-1hzo10j-94qpry6tczyhtwoc2zbqn7xto
│ │ ├── 1ewmc71fglnteipcah3q7t2tb.o
│ │ ├── dep-graph.bin
│ │ ├── query-cache.bin
│ │ └── work-products.bin
│ └── s-gzqx1i1ou2-1hzo10j.lock
├── liblib_rust.d
└── liblib_rust.rlib
9 directories, 15 files
➜ lib_rust git:(master) ✗
小结:
- 通过
cargo
指定--lib
参数创建的就是一个库package
- 输出Creating
library
lib_rust package - 和二进制package不同的是,对
库package
执行cargo run
会报错,因为库package只能作为三方库被其他项目引用 - 约定俗成:与
src/main.rs
类似,该库package的根文件是src/lib.rs
- 约定俗成:执行cargo build后,会生成两个
liblib_rust
文件,因为是库crate,所以叫lib,package叫lib_rust,所以文件名就叫liblib_rust
Crate
可执行crate
对于之前创建的hello_rust
项目,该项目下的src/main.rs
就是一个可执行的crate,可以通过rustc来编译
➜ rust cd hello_rust
➜ hello_rust git:(master) ✗ cd src
➜ src git:(master) ✗ rustc main.rs
➜ src git:(master) ✗ ll
total 912
-rwxr-xr-x 1 bytedance staff 451K 9 8 22:51 main
-rw-r--r-- 1 bytedance staff 45B 9 8 22:22 main.rs
➜ src git:(master) ✗ ./main
Hello, world!
➜ src git:(master) ✗ tree
.
├── main
└── main.rs
0 directories, 2 files
➜ src git:(master) ✗
库crate
对于之前创建的hello_rust
项目,该项目下的src/lib.rs
就是一个库crate。库crate没有main函数,它们不会被编译为可执行文件,仅提供一些诸如函数之类的,可供其他项目调用的东西
➜ rust cd lib_rust
➜ lib_rust git:(master) ✗ cd src
➜ src git:(master) ✗ cat lib.rs
pub fn add(left: u64, right: u64) -> u64 {
left + right
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}
➜ src git:(master) ✗
包和crate的关系
- 一个package只包含
0或1
个库crate - 一个package可包含
任意多个
可执行crate - 一个package
至少包含一个
库crate或可执行crate
那么如果有两个或多个可执行crate,编译器怎么知道该执行哪一个呢?
模块(module)
一个crate可以有多个module
,通过mod
关键字声明module
定义module
module里面可以嵌套module
mod zoo {
pub fn hello() {
println!("welcome to Beijing Zoo")
}
pub mod land_animals {
pub fn dog_say() {
println!("wang wang")
}
pub fn duck_say() {
println!("ga ga")
}
}
}
调用module
fn main() {
zoo::hello();
zoo::land_animals::dog_say();
zoo::land_animals::duck_say();
}
module间互相调用
- 通过
super
关键字调用父级方法 - 通过
self
关键字调用自身方法
mod zoo {
pub fn hello() {
println!("welcome to Beijing Zoo")
}
pub mod land_animals {
// 和鹦鹉聊天
pub fn parrot_talk() {
super::hello();
}
// 鹦鹉的叫声
pub fn parrot_say() {
println!("ga ga")
}
// "我”的叫声
pub fn i_say() {
self::parrot_say();
}
}
}
不同crate中mod调用
➜ hello_rust git:(master) ✗ tree
.
├── Cargo.lock
├── Cargo.toml
├── src
│ ├── america.rs
│ ├── main.rs
│ └── other
│ └── mod.rs
- 在main.rs同级目录下创建america.rs,之后在main.rs中引入america module即可使用
- 在main.rs同级目录下创建一个文件夹,而通过文件夹的方式后创建的文件名则
必须为mod.rs
,之后在main.other module即可使用 - 不同crate引用要声明
pub
才允许访问
// src/america.rs
// src/other/mod.rs
pub fn say_good() {
println!("welcome to USA zoo")
}
pub mod other;
pub mod america;
fn main() {
other::say_good();
say_good();
}
调用库中的module
lib默认的名字和package的名字一样,直接使用package的名字就可以调用库crate中的函数
// src/lib.rs
pub fn lib_hello() {
println!("lib hello")
}
// src/main.rs
fn main() {
lib_hello();
}