Box<T>
Box
— це вказівник на дані в купі:
fn main() { let five = Box::new(5); println!("five: {}", *five); }
Box<T>
реалізує Deref<Target = T>
, що означає, що ви можете викликати методи з T
безпосередньо на Box<T>
.
Рекурсивні типи даних або типи даних з динамічним розміром не можуть зберігатися вбудованими без перенаправлення вказівника. Box
здійснює цю опосередкованість:
#[derive(Debug)] enum List<T> { /// Непорожній список: перший елемент та решта списку. Element(T, Box<List<T>>), /// Порожній список. 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 хоче знати точний розмір.
- хочете передати володіння на великий обсяг даних. Щоб уникнути копіювання великих обсягів даних у стеку, натомість зберігайте дані в купі в
Box
, щоб переміщувався лише вказівник.
-
Якщо би
Box
не використовувався, і ми намагалися вставитиList
безпосередньо вList
, компілятор не зміг би обчислити фіксований розмір структури в пам’яті (List
мав би нескінченний розмір). -
Box
вирішує цю проблему, оскільки має той самий розмір, що й звичайний вказівник, і лише вказує на наступний елементList
у купі. -
Видаліть
Box
у визначенні списку та відобразіть помилку компілятора. Ми отримаємо повідомлення "recursive without indirection", тому що для рекурсії даних ми повинні використовувати посередництво,Box
або якесь посилання, замість того, щоб зберігати значення безпосередньо. -
Хоча
Box
виглядає якstd::unique_ptr
у C++, він не може бути порожнім/нульовим. Це робитьBox
одним з типів, які дозволяють компілятору оптимізувати зберігання деяких переліків ("нішова оптимізація").