tqoitc
tqoitc

Reputation: 23

"unresolved import" when using an item from a nested module

I have a small program that I've been trying to get working, but I keep getting unresolved import messages.

main.rs:

mod sub_module;
use sub_module::a_structure;

fn main() {
    let x: a_structure = /* init code */;
}

sub_module.rs:

pub mod sub_sub_module;

pub use sub_sub_module::a_structure;

sub_sub_module.rs:

pub struct a_structure<T> {
    some_field: i32,
}

However, on executing cargo build I get an "unresolved import sub_sub_module::a_structure". Everything I've found regarding visibility says that this should work however it doesn't. What am I missing here?

Upvotes: 2

Views: 1908

Answers (1)

DK.
DK.

Reputation: 59145

Think of Rust modules as being like a directory tree. Modules are directories, everything else is a file [1]. :: is basically /.

So, you have this structure:

/ (crate root)
 └┬─ sub_module
  │   └┬─ sub_sub_module
  │    │   └── a_structure
  │    └─ a_structure [x]
  ├─ a_structure
  └─ main

The problem is in how you define the a_structure [x] "symlink". As explained in the book, use paths in Rust are absolute, meaning in this analogy that they all implicitly start with /. Meaning that use sub_sub_module::a_structure is referring to /sub_sub_module/a_structure, which doesn't exist.

The solution is to use a relative path by explicitly starting the path with self (effectively .) or super (effectively ..). You want ./sub_sub_module/a_structure, so the path in Rust should be self::sub_sub_module::a_structure. A full, compiling (with warnings) example looks like:

mod sub_module {
    pub mod sub_sub_module {
        pub struct a_structure {
            some_field: i32,
        }
    }

    pub use self::sub_sub_module::a_structure;
}

use sub_module::a_structure;

fn main() {
    let x: a_structure = panic!("TODO");
}

You should also note that paths used anywhere outside of a use have the exact opposite default: they are relative to the containing module by default. If you want an absolute path in that case, you need to explicitly ask for one by starting the path with :: (just like a filesystem path that is, by default, interpreted as relative).

Aside: The conventional style is to use PascalCase for type names. Also, I had to remove the type parameter because it wasn't being used.


[1]: This is, in fact, a lie, as you can have items associated with other items. For example, associated consts, while unstable, are a thing. I suppose you could think of them in terms of resource forks or something, I don't know; it's just a metaphor!

Upvotes: 3

Related Questions