Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cross-module function call in Rust

I'm trying to call a function belonging to some module from another module (for code factoring, organization, etc).

Here is my crate structure:

➜  mod_test git:(master) ✗ tree
.
├── Cargo.lock
├── Cargo.toml
└── src
    ├── bin
    │   └── one.rs
    ├── lib
    │   └── two.rs
    └── main.rs

3 directories, 5 files

In main I declare:

pub mod bin {
    pub mod one;
}
pub mod lib {
    pub mod two;
}

and all these files simply contain a trivial pub fn main() {println!("hello");}.

At this point, everything is okay.

Now, is it possible to call lib::two::main from bin/one.rs?

None of use crate::lib::two;, use super::lib::two;, use self::super::lib::two; added in bin/one.rs work.


  • edit: I have: rustc 1.42.0 (b8cedc004 2020-03-09) installed on Linux 5.3.0-45-generic, for what it's worth.

  • edit 2: whenever using the super keyword, I get this mysterious error from rustc:

error[E0433]: failed to resolve: there are too many leading `super` keywords

and I can't find any troubleshooting about this anywhere.

  • edit 3: adding a lib.rs file in src declaring the lib module structure, and writing use mod_test::lib::two; in one.rs works, but:

    1) it defeats the idea of not multiplying "dumb module declaration files" in my crate.

    2) I have to literally copy the exact same information at two different places (in main.rs and in lib.rs)

    3) use mod_test::lib::two; is the only working syntax, using crate or super keywords still result in arcane compiler errors

like image 743
Warpig Avatar asked Apr 02 '20 14:04

Warpig


People also ask

How do you call a function from another file in Rust?

You need to make it public if you want it callable outside the sub module: pub fn sub() {...} . As for rustc, you can run cargo with a verbose flag (e.g. cargo build -v ... ) and then look at how it invokes rustc . error: Could not compile hello . To learn more, run the command again with --verbose.

How do you import a module in Rust?

To import the module, we use the keyword mod , followed by the file name without the . rs extension. When a module is imported, it allows us to use any code that's marked as public in the file we're importing the module from. Note that the module must be imported before we use any of its code.

What is a module in Rust?

Rust provides a powerful module system that can be used to hierarchically split code in logical units (modules), and manage visibility (public/private) between them. A module is a collection of items: functions, structs, traits, impl blocks, and even other modules.

What is use crate in Rust?

Keyword crate A Rust binary or library. The primary use of the crate keyword is as a part of extern crate declarations, which are used to specify a dependency on a crate external to the one it's declared in. Crates are the fundamental compilation unit of Rust code, and can be seen as libraries or projects.


1 Answers

src/bin is a special directory name to Cargo. Files in this directory are compiled as standalone binaries when you run cargo build. When compiled as binaries, they aren't part of the crate structure defined in main.rs or lib.rs.

If you just want to use bin::one as a module inside main.rs, what you have works already! You're getting error messages from compiling one.rs as a standalone binary, not from compiling main.rs with bin::one as a module. If you run cargo run --bin <name-of-project>, compilation will succeed and it will run the program in main.rs.

To tell Cargo not to compile one.rs by itself, I would suggest renaming the bin directory. This not only solves the technical problem, but also is less likely to confuse other programmers reading the project, who will expect bin to contain binaries. There may be some way to prevent Cargo from treating bin specially in this way; however, renaming it is probably the best option.

If you do want one.rs to be compiled to a separate executable that uses two, you must create a lib.rs file in the same directory as main.rs. This is also a special file to Cargo and it defines the module structure for the library crate.

// lib.rs
pub mod lib { /* note: this lib is not related to lib.rs; just unfortunately named */
    pub mod two;
}

Then inside one.rs, write use <crate-name>::lib::two;

// bin/one.rs
use mod_test::lib::two;

crate::lib::two does not work, as files inside the bin directory are compiled as standalone binaries, not as crate members; therefore, you have to call the crate by its "external" name.

adding a lib.rs file in src declaring the lib module structure, and writing use mod_test::lib::two; in one.rs works, but:

1) it defeats the idea of not multiplying "dumb module declaration files" in my crate.

2) I have to literally copy the exact same information at two different places (in main.rs and in lib.rs)

main.rs and lib.rs are two different crate roots. They are allowed to have different structure. You don't need both unless you want to generate both the binary and the library. If you want to use the library crate from inside any binary (including main.rs), it's just a use away:

use mod_test;

See also

  • Rust modules confusion when there is main.rs and lib.rs
  • Rust package with both a library and a binary?
like image 165
trent Avatar answered Sep 19 '22 10:09

trent