Skip to content

Latest commit

 

History

History
223 lines (177 loc) · 6.29 KB

File metadata and controls

223 lines (177 loc) · 6.29 KB
title Use
slug use
  • A use statement is used to bring items (types, functions, traits, modules, etc.) into the current scope.
    • It doesn't import anything; instead, it creates a local name (an alias) in the current scope.
  • This allows us:
    • to refer to items by shorter names instead of their full paths.
    • to re-export items (by publicly exposing items from another module or crate using pub use).

Path Prefixes

A use statement can start from:

  • The current crate:
    • use crate:: : Absolute path from the current crate.
    • use super:: : Relative path from the parent module.
    • use self:: : Relative path from the current module. Since Rust 2018, this is often optional.
  • External crates:
    • use my_app:: : The package name when having both main.rs/lib.rs (Cross-Crate). (my_app is the package name in the root Cargo.toml)
    • use uuid:: : Third-party crates. (uuid is a crate for UUID generation)
  • Rust library crates:
    • use std:: : Rust standard library.
    • use core:: : Rust core library. (contains functionality that does not require an operating system or a heap allocator)
    • use alloc:: : Rust core allocation and collections library. (Usually used in #![no_std] projects)

Item Selection

A use statement can select items from a path in different ways:

  • use path::item; : Bring a single item (type, function, trait, module, etc.) into scope.
  • use path::{item_a, item_b}; : Bring multiple specific items into scope.
  • use path::*; : Bring all public items from a module into scope.
  • use path::{self, item_a}; : Bring both the module itself and specific items into scope.
  • use path::nested::item; : Bring an item from a nested path into scope.
  • use path::{nested::item, nested2::item}; : Bring items from different nested modules under a shared base path in a single statement.
  • use path::item as custom_name; or use path::{self, item_a, item_b as custom_name}; : Rename items when bringing them into scope.

Re-exporting

  • Re-exporting publicly exposes items from another module or crate using pub use, allowing us to decouple the public API from internal module structure.
  • Re-exporting can be combined with visibility modifiers to control how far items are exposed within a crate.
    • pub use path::item; : Visible to anyone who can access the crate (fully public).
    • pub(crate) use path::item; : Visible anywhere inside the current crate.
    • pub(super) use path::item; : Visible only in the parent module.
    • pub(in crate::path) use path::item; : Visible only within the specified module path inside the crate.

Start from the Current Crate

use inline::nested::greet;
use inline2::greet as greet2;
use inline2::nested::greet as greet3;

fn main() {
    greet();
    greet2();
    greet3();
}

mod inline {
    pub fn greet() {
        println!("Inline");
    }

    pub mod nested {
        pub fn greet() {
            println!("Nested");
        }
    }
}

mod inline2 {
    use crate::inline; // Bring `inline` into this module's scope.

    pub fn greet() {
        inline::greet();
    }

    pub mod nested {
        pub use super::greet; // Re-export `inline2::greet` as `inline2::nested::greet`
    }
}
// ⭐️ `use crate::inline;` can move directly inside `inline2::greet()` as well.

Start from External Crates

[!lab]

cargo new my_app && cd my_app
touch src/lib.rs src/foo.rs
cargo add uuid -F v7
my_app
├── Cargo.toml    (package name my_app)
└── src
    ├── main.rs
    ├── lib.rs
    └── foo.rs

{{< tabs count=3 label="Select File" >}} {{< tab label="foo.rs" >}}

use uuid::Uuid;

pub fn new_id() -> Uuid {
    Uuid::now_v7()
}

#[cfg(test)]
mod tests {
    use super::*;
    use uuid::Version;

    #[test]
    fn test_new_id_is_version_7() {
        let id = new_id();
        assert_eq!(id.get_version(), Some(Version::SortRand));
    }
}

{{< /tab >}} {{< tab label="lib.rs" >}}

mod foo;
pub use foo::new_id;

pub struct Person {
    pub name: String,
}

pub trait Greet {
    const PREFIX: &'static str; // 💡 Required constant
    fn greet(&self) -> String; // 💡 Required method
}

impl Greet for Person {
    const PREFIX: &'static str = "Hello";

    fn greet(&self) -> String {
        format!("{} {}!", Self::PREFIX.to_owned(), self.name)
    }
}

{{< /tab >}} {{< tab label="main.rs" >}}

use my_app::{Greet, Person as Employer, new_id};

fn main() {
    let steve = Employer { name: "Steve".to_string() };
    let apple = Company { name: "Apple".to_string() };

    println!("{}", steve.greet());
    println!("{}", apple.greet());

    print!("{}", new_id())
}

struct Company {
    name: String,
}

impl Greet for Company {
    const PREFIX: &'static str = "Welcome to";

    fn greet(&self) -> String {
        format!("{} {}!", Self::PREFIX.to_owned(), self.name)
    }
}

{{< /tab >}} {{< /tabs >}}

Start from Rust Library Crates

use std::fs::{self, File}; // Bringing the `fs` module and `fs::File` struct into scope

fn main() {
    fs::create_dir("some_dir").expect("Failed to create the directory!");
    File::create("some_dir/empty.txt").expect("Failed to create the file!");
}
use core::cmp::Ordering; // Bring Ordering into scope

// Bring collections (HashMap, VecDeque), sleep, and Duration into scope
use std::{collections::{HashMap, VecDeque}, thread::sleep, time::Duration };

extern crate alloc; // Enable the alloc crate
use alloc::vec::Vec; // Bring Vec into scope

fn main() {
    let two_sec = Duration::from_secs(2);
    sleep(two_sec);

    let mut map = HashMap::new();
    map.insert("Key", 10);
    println!("map: {:?}", map);

    let mut queue = VecDeque::new();
    queue.push_back(20);
    println!("queue: {:?}", queue);

    let vec: Vec<i32> = alloc::vec![1, 2, 3];
    println!("vec: {:?}", vec);

    let (x, y) = (5, 10);
    match x.cmp(&y) {
        Ordering::Less => println!("x is smaller"),
        Ordering::Greater => println!("x is bigger"),
        Ordering::Equal => println!("x and y are equal"),
    }
}