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_ptr
em 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
Box
no heap e apenas o ponteiro Ă© movido.
-
Se
Box
nĂŁo for usado e tentarmos incorporar umList
diretamente noList
, o compilador nĂŁo conseguiria calcular um tamanho fixo da struct na memĂłria (List
teria tamanho infinito). -
Box
resolve esse problema, pois tem o mesmo tamanho de um ponteiro normal e apenas aponta para o prĂłximo elemento daList
no heap. -
Remova o
Box
na definição deList
e 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, umBox
ou 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)); }