Modules types mix up

Hi everyone,

Im trying to access a module as an object but keep getting an error. Here is an example of my project structure:

/src
  /tests
    test.rs
    another_test.rs
  main.rs

test.rs:

mod another_test;
use another_test::*;

pub struct Test {
    pub name: String,
}

impl Test {
    pub fn new() -> Self {
        Self {
            name: String::from("test"),
        }
    }

    pub fn do_test(&self, another_test: AnotherTest) {
        println!("name: {}", another_test.name);
    }
}

another_test.rs:

pub struct AnotherTest {
    pub name: String,
}

impl AnotherTest {
    pub fn new() -> Self {
        Self {
            name: String::from("another_test"),
        }
    }
}

main.rs:

#[path = "tests/test.rs"]
mod test;
use test::*;

#[path = "tests/another_test.rs"]
mod another_test;
use another_test::*;

fn main() {
    let test = Test::new();
    let another_test = AnotherTest::new();

    test.do_test(another_test); // Error! see below.
}

This is the error i get from my main function:

mismatched types
expected struct `test::another_test::AnotherTest`, found struct `another_test::AnotherTest`

The thing is that the module "another_test" is part of the test?
How I make it part of itself so I can access it everywhere?

Sorry, I'm still learning the language and I keep banging my head with the "scope" of things...

Thanks in advance!

In short:

  • mod name creates the mod and should be used only once per crate.
  • use name pull the mod in your workspace.

So, you don't need to use mod another_test in your main.rs, since it will create a new module, which is not referenced from module test. Just use test::another_test::* will do.


Side note: you're highly encouraged to use Cargo package layout. path attribute is reserved for special cases, like conditional compilation.

thanks @Cerberuser, it makes a lot of sense.

But what if I want to use the same instance of AnotherTest struct created on main with another struct?

For example (another_another_test.rs):

mod another_test;
use another_test::*;

pub struct AnotherAnotherTest {
    name: String,
}

impl AnotherAnotherTest {
    pub fn new() -> Self {
        Self {
            name: String::from("another_another_test"),
        }
    }

    pub fn do_test(&self, another_test: AnotherTest) {
        println!("name: {}", another_test.name);
    }
}

and on main function:

#[path = "tests/test.rs"]
mod test;
use test::*;

#[path = "tests/another_test.rs"]
mod another_test;
use another_test::*;

#[path = "tests/another_another_test.rs"]
mod another_another_test;
use another_another_test::*;

fn main() {
    let test = Test::new();

    let another_test = AnotherTest::new();
    let another_another_test = AnotherAnotherTest::new();

    test.do_test(another_test);

    another_test.name = String::from("reset");

    another_another_test.do_test(another_test); // Error!
}

I tried using the use crate::another_test instead of mod another_test, but it gives me the error on the main.rs file:

unresolved import `another_test`
use of undeclared type or module `another_test`

Sorry if it sounds messy has hell, but I'm really confused about the imports and using structs as instances from another files.. :stuck_out_tongue:

Side note: you're highly encouraged to use Cargo package layout. path attribute is reserved for special cases, like conditional compilation.

I will have a look at it, but this whole modules and crates and includes are really confusing...

Thanks again.

Of course. mod another_test is declared inside mod test, so the full path to it is crate::test::another_test. And again, you don't need to declare another_test in both test and another_another_test: different mod statements create different modules, not interchangable with each other.

thanks!

mod another_test is declared inside mod test , so the full path to it is crate::test::another_test

It still gives me the same error:

resolved import `another_test`use of undeclared type or module `another_test

different mod statements create different modules, not interchangable with each other.

How do I make a struct interchangable throughout the whole project then?

I guess thats what my problem is after all (sorry for the confusion once again). To have an instance of a structure accessible all over the program.

thx!

EDIT: what I'm trying to achieve is a 3D Engine, where I have all my components (mesh, transform, lights, camera, etc), renderer, math utilities, that need to be interchangable throughout the whole application.

Not sure if this will help, but what I am doing is have all the mod declarations in with my main program: ( main.rs )

mod compress;
mod bit;
mod col;
mod matcher;
mod block;
mod inflate;

fn main() 
{
...

Then in the various modules ( source files ) I have for example:

use crate::matcher;
use crate::matcher::Match;
use crate::bit::BitStream;
use crate::block::Block;

All the source files are in the same directory ( src ).

1 Like

Declare the module containing it once, with appropriate visibility, and then use it anywhere it is needed.

1 Like

thanks @geebee22

All the source files are in the same directory ( src ).

Thats my problem, Im trying to program a 3D Engine, and having all the source files in the same directory will turn into a nightmare in the future...

thanks again @Cerberuser,

Declare the module containing it once, with appropriate visibility, and then use it anywhere it is needed.

It worked! But I needed to get rid of my project structure (as geebee22 suggested) and put all the files on the same folder (src).

I know there must be something wrong with what i'm doing, and to be honest I'm still very confused about rusts file/project structure and modules and crates... Very messy! :slight_smile:

I'm gonna study it further before going deep on a 3D Engine. Its becoming obvious that the traditional OOP its just not a Rust "thing"... :frowning:

Thanks for all the tips!
:+1:

Not necessarily so. Note that, if you declare the module with path attribute, every use statement will know its file, as long as you follow the hierarchy of modules themselves - i.e. where they are declared.

It's really not the Rust thing (Rust introduces other ways to achieve the same thing), but now I'm curious, how is this connected with the module structure?

1 Like

Finally got it!! So (to get this straight), I must import everything on main.rs with mod whatever and then use::crate:: wherever I need them. It's working this way and it's finally making sense to me.

(...) how is this connected with the module structure?

I was just not "seeing it". Its definitely other way to achieve the same thing, but definitely different from c++ or java where you just import objects wherever you need them.

Thanks a lot for this reply, it made the "click"! :grin:

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.