Box<T>
Box — владеющий указатель на данные в куче:
// Copyright 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0
fn main() {
let five = Box::new(5);
println!("five: {}", *five);
}
Box<T> реализует Deref<Target = T>, что означает, что можно вызывать методы T напрямую на Box<T>.
Рекурсивные типы данных и типы данных с динамическим размером нельзя хранить напрямую без косвенности через указатель. Box обеспечивает эту косвенность:
// Copyright 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0
#[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из определения List и покажите ошибку компилятора. Мы получим сообщение «recursive without indirection», потому что для рекурсивных данных нужна косвенность —Boxили ссылка какого-то вида, — а не прямое хранение значения. -
Хотя
Boxвыглядит какstd::unique_ptrв C++, он не может быть пустым (null). Это делаетBoxодним из типов, которые позволяют компилятору оптимизировать хранение некоторых перечислений («оптимизация ниш»).