
روز ۳۰: ساخت Library کوچک در Rust؛ ورود به دنیای پروژههای ماژولار
ساخت یک Library کوچک در Rust یکی از بهترین روشها برای درک عملی crateها و مدیریت وابستگیها است. با ایجاد یک Library، شما تجربه واقعی کار با ماژولها، public API و مدیریت Error Handling را کسب میکنید. این تمرین عملی به شما کمک میکند مفاهیم روزهای گذشته، مانند mod، pub، use و Crateها را در یک پروژه واقعی پیادهسازی کنید. علاوه بر این، ساخت Library باعث میشود بتوانید کدهای خود را در پروژههای دیگر نیز مجدداً استفاده کنید و الگوی خوبی برای طراحی API تمیز و حرفهای یاد بگیرید.
ایجاد پروژه Library با Cargo
برای شروع، ابتدا یک پروژه Library با استفاده از Cargo ایجاد میکنیم. دستور زیر یک crate کتابخانهای به نام utils ایجاد میکند که میتواند شامل چندین ماژول باشد. با این کار، ساختار پروژه به شکل استاندارد ایجاد میشود و تمام امکانات Cargo مانند مدیریت وابستگیها و ساخت خودکار فایلهای مستندات در دسترس قرار میگیرد. ایجاد Library با Cargo بسیار ساده است و شما را از ایجاد دستی فایلها و تنظیمات بینیاز میکند.
cargo new utils --lib
این دستور یک پوشه به نام utils ایجاد میکند که شامل فایل src/lib.rs است. این فایل نقطه شروع Library شما محسوب میشود و تمام ماژولهای داخلی آن از اینجا export میشوند. ایجاد Library به این شکل باعث میشود که بعداً بتوانید آن را در پروژههای دیگر به راحتی اضافه و استفاده کنید.
تعریف ماژولها و توابع داخلی
در Library، بهتر است کدها را به ماژولهای منطقی تقسیم کنید. این کار باعث میشود کد خواناتر، قابل نگهداری و تستپذیرتر شود. هر ماژول میتواند توابع، structها یا Enumهای مرتبط خود را داشته باشد و با استفاده از pub و use میتوان آنها را به API عمومی Library صادر کرد. تقسیمبندی منطقی ماژولها یکی از نشانههای طراحی حرفهای در Rust است و باعث میشود Library شما آماده استفاده در پروژههای بزرگ باشد.
pub mod math {
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
pub fn subtract(a: i32, b: i32) -> i32 {
a - b
}
}در این مثال، ماژول math شامل دو تابع add و subtract است که هر دو public هستند و از خارج از Library قابل دسترسی میباشند. استفاده از pub باعث میشود مصرفکننده Library بتواند به راحتی این توابع را فراخوانی کند.
ایجاد API تمیز با re-export
برای اینکه مصرفکننده Library نیاز به دسترسی مستقیم به مسیرهای طولانی ماژولها نداشته باشد، میتوان از pub use برای re-export آیتمها استفاده کرد. این روش باعث میشود API شما ساده و قابل فهم باشد و ساختار داخلی Library را از دید کاربر مخفی نگه دارد. استفاده از re-export یکی از الگوهای رایج در پروژههای حرفهای Rust است و تجربه کاربری بهتری ایجاد میکند.
pub use crate::math::{add, subtract};با این کار، کاربران Library شما میتوانند توابع add و subtract را مستقیماً فراخوانی کنند، بدون اینکه نیاز به دانستن مسیر داخلی ماژولها داشته باشند. این الگو باعث میشود Library هم قابل استفاده و هم حرفهای به نظر برسد.
مدیریت Error Handling در Library
در طراحی Library، مدیریت خطاها بسیار حیاتی است. Rust شما را به استفاده از Result و enumهای اختصاصی برای خطاها تشویق میکند. این کار باعث میشود Library شما ایمن، قابل پیشبینی و حرفهای باشد. به جای اینکه از unwrap یا panic در توابع استفاده کنید، بهتر است خطاها را با Result به کاربر Library منتقل کنید تا او تصمیم بگیرد چگونه آنها را مدیریت کند.
pub fn divide(a: i32, b: i32) -> Result<i32, String> {
if b == 0 {
Err("Cannot divide by zero".to_string())
} else {
Ok(a / b)
}
}این مثال نشان میدهد که چطور میتوان خطاهای محتمل را به صورت صریح مدیریت کرد و تجربه کاربری امنی ایجاد نمود.
تست Library با Cargo
یکی از مهمترین ویژگیهای Rust و Cargo، امکان نوشتن تستهای داخلی است. تستها به شما کمک میکنند مطمئن شوید توابع Library همانطور که انتظار دارید کار میکنند. تستهای خودکار بخش مهمی از تولید نرمافزار حرفهای هستند و در Libraryها باعث اعتماد به کد میشوند.
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add() {
assert_eq!(math::add(2, 3), 5);
}
#[test]
fn test_divide() {
assert!(divide(10, 2).is_ok());
assert!(divide(10, 0).is_err());
}
}نوشتن تست باعث میشود تغییرات بعدی در Library بدون نگرانی از خراب شدن توابع قبلی اعمال شود.
انتشار Library و مدیریت وابستگیها
پس از تکمیل Library، میتوان آن را در پروژههای دیگر به عنوان crate داخلی یا حتی در crates.io به اشتراک گذاشت. با استفاده از Cargo، مدیریت وابستگیها بسیار ساده و قابل پیشبینی است. مصرفکنندگان Library کافی است آن را در Cargo.toml پروژه خود اضافه کنند و Cargo به صورت خودکار وابستگیها و نسخه مناسب را مدیریت میکند. این انعطافپذیری یکی از ویژگیهای قدرتمند Rust و دلیل محبوبیت آن در توسعه سیستمها و ابزارهای مقیاسپذیر است.
[dependencies]
utils = { path = "../utils" }با این تنظیم، پروژه دیگری میتواند به راحتی از Library شما استفاده کند و تمام توابع و ماژولهای public در دسترس خواهد بود.
جمعبندی تمرین عملی ساخت Library
با این تمرین عملی شما مفاهیم پایهای crateها، ماژولها، pub و use، مدیریت Error Handling و تست را در Rust تجربه کردید. ساخت Library کوچک، گام بسیار مهمی در مسیر حرفهای شدن با Rust است، زیرا در پروژههای واقعی همیشه نیاز به کدهای reusable و ایمن وجود دارد. با تکرار این تمرین و افزودن ماژولها و توابع بیشتر، میتوانید Libraryهای بزرگتر و کاربردیتر بسازید و پایه محکمی برای پروژههای پیچیده و مقیاسپذیر ایجاد کنید.