পাঠ ৭.৪

use keyword দিয়ে path scope-এ আনা

Bringing Paths Into Scope with the use Keyword

লম্বা path বারবার লেখা ক্লান্তিকর। use দিয়ে একটা shortcut বানানো যায় — অনেকটা filesystem-এর symbolic link-এর মতো।

Basic use

src/lib.rsrust
mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {}
    }
}

use crate::front_of_house::hosting;

pub fn eat_at_restaurant() {
    hosting::add_to_waitlist();
}

use-এর পরে এখন আর full path লিখতে হচ্ছে না — hosting::add_to_waitlist()

Scope-specific

use শুধু যেই scope-এ লেখা, সেই scope-এই কাজ করে। Child module-এ কাজ করবে না:

mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {}
    }
}

use crate::front_of_house::hosting;

mod customer {
    pub fn eat_at_restaurant() {
        hosting::add_to_waitlist();  // ERROR
    }
}
compile errortext
error[E0433]: failed to resolve: use of unresolved module or unlinked crate `hosting`

সমাধান — customer module-এর ভিতরে আবার use লিখো, অথবা super::hosting ব্যবহার করো।

Function — parent module import করো

Rust-এ idiom — function-এর জন্য full path-এর শেষে parent module পর্যন্ত import করা, function-টা না:

use crate::front_of_house::hosting;

pub fn eat_at_restaurant() {
    hosting::add_to_waitlist();  // ভালো — clear যে function বাইরের
}

Function-টাই import করা unidiomatic:

use crate::front_of_house::hosting::add_to_waitlist;

pub fn eat_at_restaurant() {
    add_to_waitlist();  // মনে হচ্ছে local function — confusing
}

Struct/Enum — full path import করো

Type-এর জন্য convention উল্টো — পুরো path-ই import:

use std::collections::HashMap;

fn main() {
    let mut map = HashMap::new();
    map.insert(1, 2);
}

Community-তে এই convention organic-ভাবেই দাঁড়িয়েছে।

Name conflict — as keyword

দুই module-এ same নামের type — দু'টোই দরকার:

use std::fmt;
use std::io;

fn function1() -> fmt::Result {
    // --snip--
    Ok(())
}

fn function2() -> io::Result<()> {
    // --snip--
    Ok(())
}

parent module-এর নাম দিয়ে আলাদা করা যায়। অথবা as দিয়ে rename:

use std::fmt::Result;
use std::io::Result as IoResult;

fn function1() -> Result {
    Ok(())
}

fn function2() -> IoResult<()> {
    Ok(())
}

Re-export — pub use

use-এ যা import করছ তা শুধু এই module-এ available। যদি বাইরের code-ও সেটা ঐ shortcut-এ access করতে পারে, তাহলে pub use:

mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {}
    }
}

pub use crate::front_of_house::hosting;

pub fn eat_at_restaurant() {
    hosting::add_to_waitlist();
}

pub use-এর আগে external code-কে লিখতে হত:

restaurant::front_of_house::hosting::add_to_waitlist()

এখন:

restaurant::hosting::add_to_waitlist()

Internal structure (যেমন front_of_house) লুকানো গেল, সাজানো API দিতে পারলাম। API restructuring-এর জন্য খুব useful।

External package use করা

Cargo.toml-এ dependency:

Cargo.tomltoml
[dependencies]
rand = "0.8.5"

তারপর code-এ scope-এ আনা:

use rand::Rng;

fn main() {
    let secret_number = rand::thread_rng().gen_range(1..=100);
    println!("{secret_number}");
}

Standard library (std)-ও একটা crate, কিন্তু Rust-এর সাথেই আসে — Cargo.toml-এ লিখতে হয় না। শুধু use std::... দিয়েই scope-এ আনা।

Nested path — সাজানো use list

একই module থেকে অনেক import:

use std::cmp::Ordering;
use std::io;

একটা line-এ:

use std::{cmp::Ordering, io};

এক path-ই আরেকটার subpath — self:

use std::io;
use std::io::Write;

একসাথে:

use std::io::{self, Write};

Glob — *

use std::collections::*;

সব public item import। সতর্ক — কোন নাম কোথা থেকে আসছে, পরে বোঝা কঠিন। dependency upgrade-এ surprise conflict হতে পারে। সাধারণত test module বা prelude pattern-এ ব্যবহার হয়।

এই পাঠ থেকে যা শিখলে

  • use path দিয়ে scope-এ shortcut; per-scope।
  • Function — parent module-এ থামাও; struct/enum — full path।
  • Conflict-এ as দিয়ে rename।
  • pub use — re-export, external API restructure।
  • Nested path ({cmp::Ordering, io}); self দিয়ে parent-ও যোগ; glob * সাবধানে।