<Box<T
Box یک اشارهگر مالک به دادههای روی heap است:
fn main() { let five = Box::new(5); println!("five: {}", *five); }
<Box<T ویژگی <Deref<Target = T را پیادهسازی میکند، که به این معناست که میتوانید مستقیم روشهای T را روی <Box<T فراخوانی کنید.
تایپهای دادههای بازگشتی یا انواع داده با اندازههای دینامیک را نمیتوان به صورت inline بدون pointer indirection ذخیره کرد، که میتوان با استفاده از Box آن کار را کرد:
#[derive(Debug)] enum List<T> { /// A non-empty list: first element and the rest of the list. Element(T, Box<List<T>>), /// An empty list. Nil, } fn main() { let list: List<i32> = List::Element(1, Box::new(List::Element(2, Box::new(List::Nil)))); println!("{list:?}"); }
-
Boxمانندstd::unique_ptrدر ++C است، با این تفاوت که تضمین شده است که هیچگاه تهی (null) نخواهد بود. -
Boxمیتواند زمانی مفید باشد که شما:- یک تایپ دارید که اندازه آن در زمان کامپایل مشخص نیست، اما کامپایلر Rust نیاز به دانستن اندازه دقیق آن دارد.
- میخواهید مالکیت مقدار زیادی داده را انتقال دهید. برای جلوگیری از کپی کردن حجم زیادی از دادهها در پشته، به جای آن دادهها را در heap در یک
Boxذخیره کنید تا فقط اشارهگر منتقل شود.
-
اگر از
Boxاستفاده نمیکردیم و سعی میکردیم یکListرا مستقیماً در داخلListقرار دهیم، کامپایلر نمیتوانست اندازه ثابتی برای ساختار در حافظه محاسبه کند (زیراListاندازهای بینهایت پیدا میکرد). -
Boxاین مشکل را حل میکند زیرا اندازهای برابر با یک اشارهگر عادی دارد و فقط به عنصر بعدیListدر heap اشاره میکند. -
Boxرا از تعریفListحذف کنید و خطای کامپایلر را نمایش دهید. پیام خطا “recursive without indirection” را دریافت خواهیم کرد، زیرا برای رکورسیون دادهها باید از یک روش غیرمستقیم، مانندBoxیا ارجاعی از نوعی، به جای ذخیره مستقیم مقدار استفاده کنیم.
برای کاوش بیشتر
بهینه سازی Niche
اگرچه Box مشابه std::unique_ptr در ++C به نظر میرسد، اما نمیتواند خالی/null باشد. این ویژگی باعث میشود که Box یکی از تایپهایی باشد که به کامپایلر اجازه میدهد ذخیرهسازی برخی از enumها را بهینهسازی کند.
برای مثال، <<Option<Box<T همان اندازه را دارد که <Box<T، زیرا کامپایلر از مقدار NULL برای تمایز بین variant ها به جای استفاده از تگ صریح استفاده میکند (“بهینهسازی اشارهگر خالی”):
use std::mem::size_of_val; struct Item(String); fn main() { let just_box: Box<Item> = Box::new(Item("Just box".into())); let optional_box: Option<Box<Item>> = Some(Box::new(Item("Optional box".into()))); let none: Option<Box<Item>> = None; assert_eq!(size_of_val(&just_box), size_of_val(&optional_box)); assert_eq!(size_of_val(&just_box), size_of_val(&none)); println!("Size of just_box: {}", size_of_val(&just_box)); println!("Size of optional_box: {}", size_of_val(&optional_box)); println!("Size of none: {}", size_of_val(&none)); }