[Solved] How to `use` a sibling module?

In my src directory I have the following files:

  • debris.rs
  • laser.rs
  • main.rs
  • player.rs

How do I use laser inside player if I'm using Rust 1.38?

From player module, you can use use super::laser::foo; or use crate::laser::foo;.

super refers parent module (toplevel from player), and crate refers toplevel module.

1 Like

Here's the error I get with use super::laser::LaserSpawner;

error[E0432]: unresolved import `super::laser`
  --> src/player.rs:15:12
   |
15 | use super::laser::LaserSpawner;
   |            ^^^^^ maybe a missing crate `laser`?

And the same with use crate::laser::LaserSpawner;

error[E0432]: unresolved import `crate::laser`
  --> src/player.rs:15:12
   |
15 | use crate::laser::LaserSpawner;
   |            ^^^^^ maybe a missing crate `laser`?

Oh wait...it works if I have mod laser; in main.rs

Why is this?

---Edit---
Just to provide a complete answer from the wisdom I've gained in the conversation below:

  1. Declare the laser module in the root file (main.rs) with: mod laser;
  2. Use the laser module in player with: use crate::laser;

Again, please see the conversation below for more context.
---End edit---

This is simply how the modules system works: you must declare every module if you intend to use it.

When Rust compiler sees the mod foo; statement somewhere, it will look for either of following (at the same folder):

  • foo.rs,
  • foo/mod.rs,
  • foo/foo.rs.

Any file not referenced by some mod from the root file (which would be main.rs for binary crate or lib.rs for library crates), directly or through other modules, will not be picked up.

1 Like

Very interesting. Okay I didn't realize that the root file (main.rs or lib.rs - can another file be declared as the root file?) is where the crate:: scope (or namespace or whatever) starts.

Does that same list of places to look for modules apply to use statements?

If you call rustc directly, then whatever file you pass in would be used as root, If you call it from cargo, these two filenames are hardcoded.

use statements doesn't refer to files, they refer to items. The item might be:

  • in external crate - then you'll use it as use crate_name::path::to::item;
  • in the same crate - then you'll use it as use crate::path::to::item;
  • somewhere down the modules tree - then you can use the relative path, with implicit path of current module as prefix.

For the item to be found by use, it must be declared as something - through mod statement, type declaration, and so on.

1 Like

Thank you, thank you, thank you!

Crazy how I've gotten away with not knowing this for the last 4 months of learning Rust.

I'm pretty sure it never looks for foo/foo.rs

Right, sorry - seems that I've mixed up the two real possibilities.

To be clear, you can change lib.rs or main.rs to a different file via configuration in Cargo.toml. There’s basically no reason to do so, generally, and then your crate is a teeny bit harder for others to understand.

2 Likes