Rust Organization

Mastering Function Imports & Exports in Rust

Learn how to structure and share your Rust functions like a pro.

Modules

Rust modules help you organize and split your code into logical units, making your project more maintainable as it grows.

Key Concepts
  • mod declares or imports a module
  • pub makes items accessible from outside the module
  • Each file is treated as a separate module
Project Structure
src/
main.rs
utils.rs
main.rs
mod utils; // importing local module

fn main() {
    utils::say_hello();
}

How Modules Work

When you use mod utils;, Rust will look for either:

  • A file named utils.rs in the same directory
  • A directory named utils/ with a mod.rs file inside

Exports

Making Functions Accessible

In Rust, functions are private by default. To make them accessible from other modules, you need to use the pub keyword.

Key Points
  • Mark functions with pub to make them publicly available
  • Private functions (without pub) are only accessible in the current module
  • You can also make structs, enums, traits, and modules public
utils.rs
// utils.rs
pub fn say_hello() {
    println!("Hello from utils!");
}

// Private function - only accessible within utils.rs
fn internal_helper() {
    println!("I'm only accessible inside utils.rs");
}

Visibility Rules

Understand how visibility works across different module levels:

  • 1
    Item-level visibility: Use pub to make functions, structs, or enums accessible
  • 2
    Field-level visibility: Add pub to individual struct fields
  • 3
    Restricted visibility: Use pub(crate) to limit visibility to the current crate

Export Struct Example

pub struct User {
    pub username: String,
    pub email: String,
    // Private field, not accessible outside
    password_hash: String,
}
 

Only username and email fields are accessible from other modules.

Export Module Example

// lib.rs
pub mod utils;

// utils/mod.rs
pub mod format;
mod internal; // not publicly accessible
 

The format module is accessible, but internal is not.

Imports

main.rs
mod utils;
use utils::say_hello;

fn main() {
    say_hello(); // Clean call without module prefix
}
    
 
utils.rs
pub fn say_hello() {
    println!("Hello from utils!");
}

Using Imported Functions

After exporting functions from a module, you can import them with the use keyword to simplify function calls in your code.

Import Techniques
  • First declare the module with mod utils;
  • Then import specific functions with use
  • Call the function directly without module prefix

Path Prefixes

When importing functions from different places in your module hierarchy, you'll need different path prefixes:

crate::

Absolute path from your crate root

use crate::utils::format;

super::

Path relative to parent module

use super::utils::format;

self::

Path relative to current module

use self::helper::validate;

Import Multiple Items

use utils::{
    say_hello,
    say_goodbye,
    format::format_name
};

Group multiple imports from the same module to keep your code clean and organized.

Import with Alias

use very_long_module_name::function as short_name;

fn main() {
    short_name();
}

Create aliases to avoid name conflicts or shorten very long module paths.

mod vs. use: What's the Difference?

These keywords have different purposes in the Rust module system:

mod keyword:

Declares a module, making Rust aware of its existence. Required before you can use it.

use keyword:

Brings specific items from a module into scope, allowing you to use them without the full path.

Submodules

As your Rust project grows, you'll want to organize related functionality into directories. Submodules help you structure your code in a more hierarchical way.

Directory Structure

src/
main.rs
services/
mod.rs
auth.rs

Key Components

  • 1
    mod.rs file: Acts as the entry point for a directory, declaring and re-exporting the submodules
  • 2
    Directory name: Becomes the module name when imported from parent
  • 3
    Public exports: Only functions marked as pub in submodules will be available
services/mod.rs
pub mod auth; // Make auth module available

// Re-export specific functions for convenience
pub use auth::login;
pub use auth::logout;
            

The mod.rs file declares and exports the auth submodule and re-exports specific functions.

services/auth.rs
pub fn login(username: String, password: String) -> bool {
    // Login implementation
    true
}

pub fn logout(user_id: u32) {
    // Logout implementation
}

fn hash_password(password: &str) -> String {
    // Internal function, not accessible outside
    String::from("hashed_password")
}
            

The auth.rs file contains the actual implementations, with public and private functions.

Importing from Submodules

main.rs
mod services; // Import services directory module

use services::auth::login; // Method 1: Direct path
use services::login; // Method 2: Using re-export

fn main() {
    // Both are the same function
    login("user".to_string(), "pass".to_string());
}
   

Method 1: Direct Path

Import using the full path to the function through all modules and submodules.

use services::auth::login;

Method 2: Re-exports

Import using the shorter path if the function was re-exported in mod.rs.

use services::login;

Pro Tips for Working with Submodules

  • Use re-exports strategically: Re-export commonly used functions in mod.rs to provide a cleaner API
  • Group related functionality: Organize your code based on features or domains rather than technical concerns
  • Consider modern Rust path style: Since Rust 2018, you can use mod.rs or a directory with the same name as the parent file

Real-World Examples

Structuring a Backend API

When building a real-world Rust backend, proper module organization becomes critical for maintainability and collaboration.

Benefits
  • Clean separation of concerns
  • Easier testing of isolated components
  • Reusable code across different parts of the app
  • Clear API boundaries between modules

API Project Structure Example

src/
main.rs
lib.rs
auth/
mod.rs
jwt.rs, user.rs
db/
mod.rs
models.rs, connection.rs
handlers/
mod.rs
users.rs, products.rs
utils/
mod.rs
validation.rs, logging.rs

Modular API Structure

main.rs
mod auth;
mod db;
mod handlers;
mod utils;

use handlers::{users, products};
use db::init_database;

fn main() {
    init_database();
    
    // Start server with routes
    // ...
}

The main.rs file imports all major modules and starts the application.

Module Interactions

handlers/users.rs
use crate::auth::{verify_token, User};
use crate::db::models::UserModel;
use crate::utils::validate_input;

pub async fn get_user(id: u32) -> User {
    // Implementation using other modules
    User {
        id: id,
        name: "John Doe".to_string(),
    }
}
            

Handlers import and use functions from different modules.

Key Design Principles

When structuring your Rust backend, follow these patterns for maintainable code:

Domain-Driven Design

Group files by business domain rather than by technical role to keep related code together.

Interface Segregation

Only export what's needed through mod.rs files to maintain clear module boundaries.

Dependency Inversion

Structure your modules to depend on abstractions rather than concrete implementations.

Consistent Re-exports

Use pub use statements to create a clean, consistent API for your modules.

arrow_backPrevious LessonNext Lessonarrow_forward

FAQ

Find answers to commonly asked questions about our coding courses.

No prior experience is needed for our beginner courses. We start from the absolute basics and gradually progress to more advanced concepts. For intermediate and advanced courses, we recommend having the prerequisite knowledge mentioned in the course description.

Once you purchase a course, you have lifetime access to all course materials, updates, and the community forum related to that course. We regularly update our content to keep it relevant with the latest industry standards.

Yes, we offer a 30-day money-back guarantee. If you're not completely satisfied with your purchase, you can request a full refund within 30 days of enrollment. No questions asked.

Most courses require about 4-6 hours per week to complete in a reasonable time frame. However, our platform is self-paced, so you can learn according to your own schedule. Each course indicates the estimated completion time in the description.

Yes, all courses come with a certificate of completion that you can add to your resume or LinkedIn profile. For some advanced courses, we also offer industry-recognized certifications upon passing the final assessment.

You'll have access to our community forum where you can ask questions and get help from instructors and fellow students. Premium courses include direct mentor support, code reviews, and weekly live Q&A sessions.

Still Have Questions?

Learning Resources

Access our free tutorials, coding challenges, and community projects to supplement your learning.

Browse Resources

Blog & Tech News

Stay updated with the latest programming trends, tips, and industry insights from our expert instructors.

Read Blog