Box<T>
Box é um ponteiro owned para dados no heap:
fn main() { let five = Box::new(5); println!("cinco: {}", *five); }
Box<T> implementa Deref<Target = T>, o que significa que você pode chamar métodos de T diretamente em um Box<T>.
Tipos de dados recursivos ou tipos de dados com tamanhos dinâmicos precisam usar uma Box:
#[derive(Debug)] enum List<T> { /// Uma lista não vazia: primeiro elemento e o resto da lista. Element(T, Box<List<T>>), /// Uma lista vazia. Nil, } fn main() { let list: List<i32> = List::Element(1, Box::new(List::Element(2, Box::new(List::Nil)))); println!("{list:?}"); }
-
Boxé parecido comstd::unique_ptrem C++, exceto que ele é garantidamente não nulo. -
Uma
Boxé útil quando você:- há um tipo cujo tamanho não está disponível em tempo de compilação, mas o compilador Rust precisa saber o tamanho exato.
- quer transferir o ownership de um grande volume de dados. Ao invés de copiar grandes volumes de dados na pilha, eles são armazenados usando uma
Boxno heap e apenas o ponteiro é movido.
-
Se
Boxnão for usado e tentarmos incorporar umListdiretamente noList, o compilador não conseguiria calcular um tamanho fixo da struct na memória (Listteria tamanho infinito). -
Boxresolve esse problema, pois tem o mesmo tamanho de um ponteiro normal e apenas aponta para o próximo elemento daListno heap. -
Remova o
Boxna definição deListe mostre o erro de compilação. Nós obtemos a mensagem “recursive without indirection” (recursivo sem indireção), porque para recursão de dados, temos que usar indireção, umBoxou referência de algum tipo, ao invés de armazenar o valor diretamente.
Mais para Explorar
Otimização de Nicho
Embora Box pareça com std::unique_ptr em C++, ele não pode ser vazio/nulo. Isso faz com que Box seja um dos tipos que permitem ao compilador otimizar o armazenamento de alguns enums.
Por exemplo, Option<Box<T>> tem o mesmo tamanho que apenas Box<T>, porque o compilador usa o valor NULL para discriminar as variantes em vez de usar uma tag explícita (“Null Pointer Optimization”):
use std::mem::size_of_val; struct Item(String); fn main() { let just_box: Box<Item> = Box::new(Item("Apenas box".into())); let optional_box: Option<Box<Item>> = Some(Box::new(Item("Box opcional".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!("Tamanho de just_box: {}", size_of_val(&just_box)); println!("Tamanho de optional_box: {}", size_of_val(&optional_box)); println!("Tamanho de none: {}", size_of_val(&none)); }