57

I can't find how to include (or import, inject, or some other word) a function from one file (module) to another.

I start a new project with

$ cd ~/projects
$ cargo new proj --bin
$ cd proj
$ tree
.
|
-- Cargo.toml
-- src
   |
   -- main.rs

I modify main.rs and create a new file a.rs (inside the src dir) with the following code:

main.rs

fn main() {
    println!("{}", a::foo());
}

a.rs

pub fn foo() -> i32 { 42 }

I run the project with cargo run and get the error:

error[E0433]: failed to resolve: use of undeclared type or module `a`
 --> src/main.rs:2:20
  |
2 |     println!("{}", a::foo());
  |                    ^ use of undeclared type or module `a`

It seems that I need to import the a somehow. I tried to add following things as a first line to main.rs

  • use a;

    error[E0432]: unresolved import `a`
     --> src/main.rs:1:5
      |
    1 | use a;
      |     ^ no `a` in the root
    
  • use a::*;

    error[E0432]: unresolved import `a`
     --> src/main.rs:1:5
      |
    1 | use a::*;
      |     ^ maybe a missing `extern crate a;`?
    
    error[E0433]: failed to resolve: use of undeclared type or module `a`
     --> src/main.rs:4:20
      |
    4 |     println!("{}", a::foo());
      |                    ^ use of undeclared type or module `a`
    
  • use a::foo;

    error[E0432]: unresolved import `a`
     --> src/main.rs:1:5
      |
    1 | use a::foo;
      |     ^ maybe a missing `extern crate a;`?
    
    error[E0433]: failed to resolve: use of undeclared type or module `a`
     --> src/main.rs:4:20
      |
    4 |     println!("{}", a::foo());
      |                    ^ use of undeclared type or module `a`
    
  • extern crate a; use a::foo;

    error[E0463]: can't find crate for `a`
     --> src/main.rs:1:1
      |
    1 | extern crate a;
      | ^^^^^^^^^^^^^^^ can't find crate
    
  • extern crate proj; use proj::a::foo;

    error[E0463]: can't find crate for `proj`
     --> src/main.rs:1:1
      |
    1 | extern crate proj;
      | ^^^^^^^^^^^^^^^^^^ can't find crate
    

I have read the guide but still cannot figure out how to do imports.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
vil
  • 917
  • 1
  • 8
  • 12

3 Answers3

57

In a mainish module (main.rs, lib.rs, or subdir/mod.rs), you need to write mod a; for all other modules that you want to use in your whole project (or in the subdir).

In any other module, you need to write use a; or use a::foo;

You're far from the only person to be confused by this, and it's certainly possible to do better, but any changes to the module system will get rejected as "too confusing".

Edit: this answer was written for the "Rust 2015" language standard. Changes were made for the "Rust 2018" standard, see this blog post and the edition guide

matiu
  • 7,469
  • 4
  • 44
  • 48
o11c
  • 15,265
  • 4
  • 50
  • 75
  • 1
    So when is `extern crate` necessary? I thought every Rust file was a separate crate (unit of compilation). – voithos Oct 06 '14 at 21:34
  • 3
    @voithos Your main.rs or lib.rs and all the files it recursively revers via `mod` instructions will be compiled as a crate. This is the unit of compilation. – Levans Oct 06 '14 at 22:03
  • 36
    `but any changes to the module system will get rejected as "too confusing"` The existing module system is "too confusing". – Qix - MONICA WAS MISTREATED Apr 23 '15 at 03:32
  • I find this answer confusing, you suggest to put `mod a;` in main, and in secondary files `use a;` - shouldn't it be the other way around - my main is using stuff from other files.. – dark_ruby May 17 '16 at 09:47
  • Thanks, the solution "mod a; in main.rs, and use a; in a.rs" works for me. – Olivier de Rivoyre Jan 28 '17 at 10:36
  • 9
    I've spent **an hour** trying to figure this out. No other language has an import system with so many different keywords, meanings, nuances, and non-obvious features. – Mateen Ulhaq May 03 '18 at 07:03
  • 4
    I literally spent 40 minutes to find what you've stated here, despite reading doc on modules several times. I have years of experience with around 3 languages pretty intensively and I guess around 10 langs in total overall. The module system in Rust by far is the most unnecessary overcomplication I've ever seen... – Dmitry Kankalovich Apr 22 '20 at 02:56
  • As others have stated - too messy! Rust is my ~10th language and I have spent a couple of hours just trying to do basic importing. I heard that Rust took a while to learn, and I was thinking about the more advanced concepts, not importing....this is ridiculous. Even C/C++ did this better. Slightly disappointed... – NullPumpkinException Aug 06 '21 at 09:08
25

In Rust, there are some keywords to deal with modules:

mod

mod has two forms:

  • when used with curly braces it declares a module (namespace).
  • when used with just a name, it will look for the module in the local filesystem.

A module can be:

  • a file with extension .rs, or
  • a folder with a file named mod.rs

use

use imports a name into the current module's namespace. We can use any function, struct, enum, type alias, trait, or (sub)module. The use clause is pretty strict, if we state use module1::moduleA; no other name from module1 will be available but moduleA. An asterisk (*) can be used to use everything within a module: use module1::*;. Sets can be used as well: use module1::{moduleA, moduleB};

An example:

| main.rs
|- module1
      |- mod.rs
      |- moduleA.rs
      |- moduleB.rs

mod.rs contains:

pub mod moduleA; // declare a child module
pub mod moduleB; // declare a child module

main.rs contains:

// use what Cargo downloaded (not necessary in Rust 2018)
//extern crate that_one_thing_i_need;

///  ======

mod module1; // declare a child module

// some local stuff I want to scope
mod local {
    pub fn my_function() {}
}

//   ======

// make the symbols locally available:
use module1::moduleA::*;
use module1::moduleB::{functionX, moduleY, typeZ};

// To avoid having to write `that_one_thing_i_need::` a lot,
// we can make local aliases that will be valid in the current module.
use that_one_thing_i_need::fancy_stuff as fs;

///  ======

fn main() {
    // we can use anything here from the namespaces we are using:
    //      moduleA
    //      functionX
    //      moduleY
    //      typeZ
    //      fs

    // We can access stuff by navigating from the outermost visible
    // module name
    local::my_function();
}

Symbols are only usable from within the module. If you want to cross this barrier (even on a locally declared module) we need to make them public using the keyword pub.

extern crate

extern crate fills the gap between Cargo and Rust. We write code in a .rs file, this file can be compiled with rustc. Cargo will manage external dependencies and call rustc. The extern crate ... line tells the compiler to look for this namespace, so it is unambiguous.

Editor's noteextern crate is not required in many cases if you are using the Rust 2018 edition.

trent
  • 25,033
  • 7
  • 51
  • 90
Luis Ayuso
  • 2,967
  • 1
  • 14
  • 15
  • How to write if `moduleA` needs stuff from `moduleB` ? And maybe vice versa? – Matthias Feb 23 '19 at 16:50
  • I was struggling with exactly that scenario (a module importing something from its 'sibling' or direct 'parent') multiple times in the past and still do. The short answer is to `use crate::parent` or `use crate::sibling`. – Daniel Schütte Mar 22 '19 at 00:28
  • I would discourage from having mutual dependecies in any scenario. A more carefull desing where common dependencies are extracted into another entity woudl a more elegant solution. – Luis Ayuso Oct 31 '19 at 13:20
6

I am very late to the party, but one way to split your code into multiple files without affecting the scoping too much is the following.

Imagine a folder structure like this, for a book handling library:

src/
  lib.rs
  author.rs
  book.rs

You can do:

// lib.rs
// --------------
mod author;
use author::*;
mod book;
use book::*;

// author.rs
// --------------
struct Author {
    name: String,
    birth_year: i32,
}

// book.rs
// --------------
use super::*;

struct Book {
   title: String,
   author: Author,  // Author is in scope
   isbn: i64,
}

This structure emulates Go modules (everything in the folder seems to be in the same scope).

Another ways would be (a bit more python-style):

// lib.rs
// --------------
mod author;
mod book;

// book.rs
// --------------
// either so, to import everything
use super::*;
// or so, one line per peer-module
use super::author;

struct Book {
   title: String,
   author: author::Author,  // Author is in scope
   isbn: i64,
}
Francesco Pasa
  • 511
  • 6
  • 14