Skip to content

Better documentation for "No more mod.rs" #104

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
KiChjang opened this issue Sep 17, 2018 · 21 comments
Closed

Better documentation for "No more mod.rs" #104

KiChjang opened this issue Sep 17, 2018 · 21 comments
Labels
question Further information is requested

Comments

@KiChjang
Copy link
Member

https://rust-lang-nursery.github.io/edition-guide/rust-2018/module-system/path-clarity.html#no-more-modrs

In Rust 2018, mod.rs is no longer needed. foo.rs can just be foo.rs, and the submodule is still foo/bar.rs. This eliminates the special name, and if you have a bunch of files open in your editor, you can clearly see their names, instead of having a bunch of tabs named mod.rs.

Emphasis mine. I discovered that this does not mean that mod.rs can be eliminated from your projects once and for all -- instead, it means specifically that in the case where you have only src/foo/mod.rs, you can instead name it src/foo.rs and it'll work just fine.

@KiChjang
Copy link
Member Author

Further investigation has caused me to believe that the intended way of having no mod.rs is to first have a src/foo.rs, and then have src/foo/bar.rs, which would cause use self::foo::bar; to succeed.

@KiChjang KiChjang changed the title "No more mod.rs" is misleading Better documentation for "No more mod.rs" Sep 17, 2018
@ZhangHanDong
Copy link
Contributor

@KiChjang Agree with you.

@steveklabnik
Copy link
Member

It's not clear to me what this ticket means. Could you help point me to what needs to be clarified?

@steveklabnik steveklabnik added the question Further information is requested label Sep 18, 2018
@KiChjang
Copy link
Member Author

KiChjang commented Sep 19, 2018

@steveklabnik It's not clear from the documentation that if you transition from a project that had a src/foo/mod.rs before means that you need to rename and move that file to src/foo.rs. My initial reading of it felt like you could just remove src/foo/mod.rs altogether and the project would still compile, leading to surprises when I attempted to import self::foo::bar, where bar is any submodule under foo.

@steveklabnik
Copy link
Member

Do you have any suggestions on what should change? I'm having a hard time seeing how you got to that. I'd still like to improve this though!

@KiChjang
Copy link
Member Author

Perhaps instead of saying that mod.rs is no longer needed, it may be better to say that you can replace src/foo/mod.rs with src/foo.rs, because the module (and hence the functionality of mod.rs) is still being declared; it's just not called mod.rs anymore and not located in the same location.

Conversations with @ZhangHanDong has informed (or really, reminded) me that this is how Rails imported its modules, so perhaps there is some text in the Rails documentation that we could reference...

@ZhangHanDong
Copy link
Contributor

@steveklabnik @KiChjang

I submitted a PR

@ZhangHanDong
Copy link
Contributor

@KiChjang PR have been merged. this issues should be closed.

@Timmmm
Copy link

Timmmm commented Jun 11, 2019

Sorry but the documentation is still not clear:

In Rust 2015, if you have a submodule:

///  foo.rs
///  or
///  foo/mod.rs

mod foo;

It can live in foo.rs or foo/mod.rs. If it has submodules of its own, it must be foo/mod.rs. So a bar submodule of foo would live at foo/bar.rs.

This is ok, but:

In Rust 2018, mod.rs is no longer needed.

///  foo.rs
///  foo/bar.rs

mod foo;

/// in foo.rs
mod bar;

Sorry what? It is not clear at all what is in which file. Following the above example it seems to say that mod foo; should be in foo.rs or foo/bar.rs (surely not?), and mod bar; should ... also .. be in foo.rs?? What is the intended directory structure here?

Also I would have thought that foo/foo.rs was a reasonable place to look for mod foo;. That way you can put all of the code for a module (and its submodules) in its own directory. It seems like "no more mod.rs" means "no more mod.rs as long as you don't mind module code spewing into its parent directory?"

@Timmmm
Copy link

Timmmm commented Jun 11, 2019

Here is a better way to word it I think:

In Rust 2015 if you declare mod foo; it will look for the module in the following places (relative to the file containing the mod foo; declaration):

  • foo.rs
  • foo/mod.rs

However if the foo module has submodules of its own it must be at foo/mod.rs. A submodule bar could be at foo/bar.rs or foo/bar/mod.rs.

In Rust 2018 this restriction is lifted. If the foo module is implemented in foo.rs Rust will look for its bar submodule at foo/bar.rs or foo/bar/mod.rs.

Assuming that is correct.

@ehuss
Copy link
Contributor

ehuss commented Jul 21, 2019

@Timmmm I have posted a PR at #187. Can you take a look and let me know what you think?

@Timmmm
Copy link

Timmmm commented Jul 22, 2019

Much clearer, thanks! I think it is probably also worth highlighting the fact that if you want to keep all of your module files in a subdirectory, you still have to use mod.rs. Initially when I heard "no need to use mod.rs anymore!" I thought I would just be able to rename mod.rs to foo.rs, or something like that, but that isn't the case (presumably because that file is already used for foo::foo). Something like this at the end:

If you wish to keep all foo-related files in the foo directory then you must still use mod.rs. You cannot simply rename foo/mod.rs to foo/foo.rs because that is the path for a submodule of foo, also called foo.

@jinmingjian
Copy link

jinmingjian commented Sep 22, 2019

I re-read this chapter again today. These words in this changed section have problem truly.

what Timmmm said above's above... is right. The comments for mod decl after "In Rust 2018..."

///  foo.rs
///  foo/bar.rs

mod foo;
...

make no sense ... two files? which files?

The fact should be that "mod foo" should be declared in its parent(mod), like in "lib.rs".

@Timmmm your above idea is not right. "No more mod.rs" is true. You can have no mod.rs for modules now. I suggest you do some tries. This is why I/we should advocate the 2018 style.

So, I suggest to reopen this idea and correct the problem.

@ehuss
Copy link
Contributor

ehuss commented Sep 22, 2019

@jinmingjian Have you seen the rewritten version? It is available in the beta or nightly docs: https://doc.rust-lang.org/beta/edition-guide/rust-2018/module-system/path-clarity.html#no-more-modrs This should hit stable next week (it unfortunately takes a while to ride the train to stable).

@jinmingjian
Copy link

@ehuss thanks for pointing this beta edition-guide! It is great!

It is interesting to see we do different changes to different versions of the same docs. A little mess...

OK, I may live with nightly docs: https://doc.rust-lang.org/nightly/edition-guide/rust-2018/module-system/path-clarity.html#no-more-modrs , rather than fooled by the search engine:smiley:.

@Timmmm
Copy link

Timmmm commented Sep 25, 2019

@Timmmm your above idea is not right. "No more mod.rs" is true

No it isn't. It is "No more mod.rs if you are ok with moving the (former) mod.rs file into its parent directory".

To put it another way, "no more mod.rs" implies that there is never any reason to use mod.rs any more. But actually you can only eliminate mod.rs if you structure your files in a quite awkward way (IMO).

@jinmingjian
Copy link

@Timmmm Yes. I eliminate the mod.rs in my project. And in fact, I've seen several big projects done this. OK, YMMV. But I suggest who read this issue can do your own try.

@art-in
Copy link

art-in commented Nov 16, 2019

I've tried both structures (with and without mod.rs), and it works ok in both editions (2015 and 2018).

└── foo/
    ├── mod.rs
    └── bar.rs
├── foo.rs
└── foo/
    └── bar.rs

The section is confusing, as I'm new to rust. Let me clarify.

In Rust 2015 ... It (mod foo) can live in foo.rs or foo/mod.rs. If it has submodules of its own, it must be foo/mod.rs.

I have edition 2015, foo has submodules, and still I can put it in both foo.rs and foo/mod.rs.
The restriction existed in 2015 before, but was eliminated at some point, right?

No more mod.rs

I have no errors for having mod.rs in both editions.
It means, "mod.rs is not required anymore" (for modules with submodules), right?

if you have a bunch of files open in your editor, you can clearly see their names, instead of having a bunch of tabs named mod.rs.

That's why e.g. vscode shows path when several tabs with same names are opened.

d6a46d635baa0459e8448abcfa559285

So if I prefer mod.rs, it is still ok to use it, right?

@ehuss
Copy link
Contributor

ehuss commented Nov 16, 2019

The restriction existed in 2015 before, but was eliminated at some point, right?
It means, "mod.rs is not required anymore" (for modules with submodules), right?
So if I prefer mod.rs, it is still ok to use it, right?

Support for non-mod-rs files was stabilized in both editions in the 1.31 release. You are free to use either style on both editions.

Some of the confusion may be because the edition guide was written in such a way that "Rust 2015" meant how code was written around the 1.0 release, and "2018" was how code can be written after the 1.31 release. It sort of provides the highlights of the changes in the 3 years between May 2015 and Dec 2018. It does not necessarily mean certain things can only be done when you declare the edition as "2018". There is a page at https://doc.rust-lang.org/edition-guide/rust-2018/edition-changes.html that explicitly lists the actual differences between the two.

@art-in
Copy link

art-in commented Nov 16, 2019

Ok, I would at least add something like this to the end of this section:
"Both approaches are allowed in editions 2015 and 2018 starting from v1.31".

Also I would change it's title, since it's misleading ("No more mod.rs").
It's obviously aligned with "No more extern crate" title, but it makes more sense for extern crate as it just doesn't do anything anymore, while mod.rs is still valid approach if you want to keed your module in self-contained folder. "mod.rs is not required anymore" sounds better for me.

And lastly it shouldn't state "In Rust 2015..." / "In Rust 2018..." if it is not about edition anyore, but rather compiller version. Maybe something like ""In Rust 2015 (before 1.31)...".

@VCCICCV
Copy link

VCCICCV commented Aug 27, 2024

1、 在Rust 1.30之前使用mod.rs来定义模块和嵌套子模块

cargo new demo

src\util\bar.rs

pub fn print_src_bar() {
    println!("bar");
}

src\util\foo.rs

pub fn print_src_foo() {
    println!("foo");
}

src\util\mod.rsmod.rs定义的内容编译器会找同级目录的bar.rsbar\mod.rs文件

// 公开模块识别crate
pub mod bar;
pub mod foo;

main.rs:crate root

mod util;

use crate::util::{bar, foo};
fn main() {
    bar::print_src_bar();
    foo::print_src_foo();
}

执行cargo run成功调用方法

bar
foo

也可以直接在util\mod.rs里编写方法,比如路由

pub mod bar;
pub mod foo;
// 公开模块才能识别到crate和方法
pub mod routes{
    pub fn routes(){
        println!("routes");
    }
}

main.rs:crate root

mod util;
use crate::util::{ bar, foo };
use crate::util::routes::routes;
fn main() {
    bar::print_src_bar();
    foo::print_src_foo();
    routes();
}

2、 在Rust 1.30之后,直接创建子模块,不需要mod.rs

cargo new demo

src\util\bar.rs

pub fn print_src_bar() {
    println!("bar");
}

src\util\foo.rs

pub fn print_src_foo() {
    println!("foo");
}
  1. main.rs声明``crate`
mod util{
    pub mod bar;
    pub mod foo;
}
use util::bar;
use util::foo;

fn main() {
    bar::print_src_bar();
    foo::print_src_foo();
    println!("main");
}

执行cargo run成功调用方法

bar
foo
main
  1. 使用<folder_name>.rs

新建一个src\util.rs

pub mod bar;
pub mod foo;

main.rs

mod util;
use crate::util::bar;
use crate::util::foo;
fn main() {
    bar::print_src_bar();
    foo::print_src_foo();
    println!("main");
}

执行cargo run

bar
foo
main

Rust多模块应用

  • 使用[workspace]使子模块依赖于一个Cargo.toml,共享一个target输出目录

  • 使用cargo new --lib新建子模块,在根目录Cargo.toml添加[workspace]来嵌套子模块

创建父项目

cargo new demo

创建子模块

cargo new --lib application

application\src\util\app_bar.rs

pub fn print_app_bar() {
    println!("app_bar");
}

application\src\util\app_foo.rs

pub fn print_app_foo() {
    println!("app_foo");
}

application\src\lib.rs

pub mod util{
    pub mod app_bar;
    pub mod app_foo;
}

如果有依赖要导入到当前模块中使用

// 在lib.rs添加
pub use sea_orm_migration::prelude::*;
// 在要使用的crate中添加
use sea_orm_migration::prelude::*;

在父项目根目录的Cargo.toml添加

[workspace]
members = [".","application"]
[dependencies]
application = {path = "application"}

src\main.rs

use application::util::app_bar;
use application::util::app_foo;
fn main() {
    app_bar::print_app_bar();
    app_foo::print_app_foo();
    println!("main");
}

执行cargo run

app_bar
app_foo
main

新建其他模块同样的套路,cargo new --lib 模块名,父项目的Cargo.toml会自动添加

[workspace]
members = [".","application", "模块名"]

要使用哪个模块的方法就在哪个模块的Cargo.toml添加[dependencies]并指定路径path,比如实体定义在entity模块中,在serviceCargo.toml添加

[dependencies]
entity = { path = "../entity" }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

8 participants