https://doc.rust-lang.org/edition-guide/rust-2018/module-system/path-clarity.html
模块在官网上被誉为新手死亡问题:
The module system is often one of the hardest things for people new to Rust. Everyone has their own things that take time to master, of course, but there’s a root cause for why it’s so confusing to many: while there are simple and consistent rules defining the module system, their consequences can feel inconsistent, counterintuitive and mysterious.
连续三天,在干了有限的论坛帖子和全部的官方资料后,终于明白了Rust模块的管理。在看本文之前,你首先要对Rust的模块管理有基本的了解:
7.使用包、Crate和模块管理不断增长的项目
此前我已经阅读了官方的两个文档(书和reference),但是在学习Diesel的过程中,注意到它用的use引入包方式不一样(后来发现是2015版本),在改成2018版本过程中,引发了一系列问题…现在解决了,所以把结论分享出来。
use crate::xxx::yyy
如果a.rs是库的碎片,crate是库的root,如果a.rs是可执行文件,crate是它自己。
use self::schema::posts; // 因为Cargo.toml没有分别命名,所以二进制文件和库有同样的名字,所以self此时代表的也是库的root
use desel_demo::schema::posts; //就像第三方依赖,可以用库名访问它
use desel_demo::xxx::yyy
这一点和第三方库一致,假设用到的第三方库是diesel,也是用:
use diesel::xxx
// 碎片a和b是姐妹,假设他们是库root的孩子——绝对路径
use crate::b
// 碎片b是a的孩子——相对路径
use b
// 碎片b是a的孙子——相对路径
use some_child::b
// 重孙子....
不管是什么情况,都不会有碎片a
use b
这是因为,能用use b的,要么b是个第三方库,要么b是自己的库(如果自己是二进制文件,并且b的名字在package的lib的name里),这点和第二点是一个意思。
在库中引用库碎片:
use self::schema::posts; // 如果当前文件是库的root,也就是lib.rs或任意二进制文件——bin/some_binary.rs或main.rs
use super::schema::posts; // 假设当前文件是库的root下面一个rs文件,比如model.rs,它的super是root,所以可以用super::schema
在库中引用库碎片不能用:
use desel_demo::xxx; // 因为desel_demo是它自己
extern crate xxx
。这个在2015里,对第三方库、第三方宏、和自己的库(root)都需要声明,在2018里不再需要,但是在2018里,它们依然可以用。但是对于2015的宏引入方式,可以一次性引入依赖的所有宏,对于宏嵌套的情况尤其好用;如果用2018的方式,需要逐个引入所用的所有宏,包括嵌套的宏。// Rust 2015
#[macro_use]
extern crate bar;
fn main() {
baz!();
}
// Rust 2018
use bar::baz;
fn main() {
baz!();
}
[lib]
的name
修改,否则也是package的名字。│ .env
│ Cargo.lock
│ Cargo.toml
│ diesel.toml
│
├─migrations
│ ├─00000000000000_diesel_initial_setup
│ │ down.sql
│ │ up.sql
│ │
│ └─20160815133237_create_posts
│ down.sql
│ up.sql
│
├─src
│ │ lib.rs
│ │ models.rs
│ │ schema.rs
│ │
│ └─bin
│ show_posts.rs
│ write_post.rs
│
└─target
lib.rs
:
pub mod models;
pub mod schema;
use diesel::prelude::*;
use dotenv::dotenv;
use std::env;
#[macro_use]
extern crate diesel;
// use models::{NewPost, Post} // 方法1. 相对路径省略self
// use self::models::{NewPost, Post}; // 方法2, 相对路径
use crate::models::{NewPost, Post}; // 方法3, 绝对路径
pub fn establish_connection() -> MysqlConnection {
dotenv().ok();
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
MysqlConnection::establish(&database_url)
.unwrap_or_else(|_| panic!("Error connecting to {}", database_url))
}
pub fn create_post(conn: &MysqlConnection, title: &str, body: &str) -> Post {
use schema::posts;
let new_post = NewPost { title, body };
diesel::insert_into(posts::table)
.values(&new_post)
.execute(conn)
.expect("Error saving new post");
posts::table.order(posts::id.desc()).first(conn).unwrap()
}
models.rs
use diesel::{Queryable,Insertable};
// use super::schema::posts; 方法1,相对路径
use crate::schema::posts // 方法2,绝对路径(不能用依赖名称)
#[derive(Queryable)]
pub struct Post {
pub id: i32,
pub title: String,
pub body: String,
pub published: bool,
}
#[derive(Insertable)]
#[table_name = "posts"]
pub struct NewPost<'a> {
pub title: &'a str,
pub body: &'a str,
}
schema.rs
// use diesel::table; 2018方式,需要引入其他的嵌套宏;
// lib.rs用了2015的#[macro_use],引入所有的diesel宏
table! {
posts (id) {
id -> Integer,
title -> Varchar,
body -> Text,
published -> Bool,
}
}
show_posts.rs
// use diesel_demo::models::*; 方法1,绝对路径,通过依赖名称引入
// use self::models::*; 方法2,相对路径同名依赖子模块
// use models::*; 方法3,相对路径中的self可以省略
use crate::models::*; // 方法4, 绝对路径,通过crate关键字引入
use diesel::prelude::*;
use diesel_demo::*;
fn main() {
// use diesel_demo::schema::posts::dsl::*; // 方法1
// use self::schema::posts::dsl::*; // 方法2
// use schema::posts::dsl::*; // 方法3
use crate::schema::posts::dsl::*; // 方法4
let connection = establish_connection();
let results = posts
.filter(published.eq(true))
.limit(5)
.load::(&connection)
.expect("Error loading posts");
println!("Displaying {} posts", results.len());
for post in results {
println!("{}", post.title);
println!("-----------\n");
println!("{}", post.body);
}
}
Compiling diesel_api v0.1.0 (G:\workspace_rh\bbc\study2\diesel_demo)
Runningrustc --crate-name diesel_api --edition=2018 src/lib.rs --error-format=json --json=diagnostic-rendered-ansi --crate-type lib --emit=dep-info,metadata,link -C embed-bitcode=no -C debuginfo=2 -C metadata=fe739cf32ff0b44a -C extra-filename=-fe739cf32ff0b44a --out-dir 'G:\workspace_rh\bbc\study2\diesel_demo\target\debug\deps' -C 'incremental=G:\workspace_rh\bbc\study2\diesel_demo\target\debug\incremental' -L 'dependency=G:\workspace_rh\bbc\study2\diesel_demo\target\debug\deps' --extern 'diesel=G:\workspace_rh\bbc\study2\diesel_demo\target\debug\deps\libdiesel-7a9409e220aa80ac.rmeta' --extern 'dotenv=G:\workspace_rh\bbc\study2\diesel_demo\target\debug\deps\libdotenv-dca3ca0087910b06.rmeta' -L 'native=C:\Program Files\MySQL\MySQL Connector C 6.1\lib\vs14'
Runningrustc --crate-name diesel_api --edition=2018 'src\main.rs' --error-format=json --json=diagnostic-rendered-ansi --crate-type bin --emit=dep-info,link -C embed-bitcode=no -C debuginfo=2 -C metadata=8c1c4d3f22495238 --out-dir 'G:\workspace_rh\bbc\study2\diesel_demo\target\debug\deps' -C 'incremental=G:\workspace_rh\bbc\study2\diesel_demo\target\debug\incremental' -L 'dependency=G:\workspace_rh\bbc\study2\diesel_demo\target\debug\deps' --extern 'diesel=G:\workspace_rh\bbc\study2\diesel_demo\target\debug\deps\libdiesel-7a9409e220aa80ac.rlib' --extern 'diesel_api=G:\workspace_rh\bbc\study2\diesel_demo\target\debug\deps\libdiesel_api-fe739cf32ff0b44a.rlib' --extern 'dotenv=G:\workspace_rh\bbc\study2\diesel_demo\target\debug\deps\libdotenv-dca3ca0087910b06.rlib' -L 'native=C:\Program Files\MySQL\MySQL Connector C 6.1\lib\vs14'
Finished dev [unoptimized + debuginfo] target(scargo) in 37.52s
Runningtarget\debug\diesel_api.exe
https://stackoverflow.com/questions/57756927/rust-modules-confusion-when-there-is-main-rs-and-lib-rs
https://doc.rust-lang.org/edition-guide/rust-2018/module-system/path-clarity.html
2018和2015区别
https://doc.rust-lang.org/cargo/guide/project-layout.html
package应有的结构
https://doc.rust-lang.org/edition-guide/rust-2018/macros/macro-changes.html
2018和2015对宏引用的区别