Box<T>

O Smart Pointer Box, é bem versátil, ele aponta para a heap e também implementa as traits Deref e DerefMut, sendo assim, é possível apontar para um endereço de memória na Heap e realizar modificações nesta região de memória. Vamos a um exemplo mais simples.

fn main() {
    let numero: Box<usize> = Box::new(42);
    println!("{}", numero);
}

Neste exemplo acima, apontamos para uma região da heap, um número inteiro sem sinal, o Box, obedece às mesmas regras de ownership que ponteiros comuns.

Como ele foi declarado como imutável, não podemos fazer o DerefMut e alterar o valor na heap, caso tentarmos fazer isso teremos o seguinte erro.

fn main() {
    let numero: Box<usize> = Box::new(42);
    *numero = 69;
    println!("{}", numero);
}
error[E0594]: cannot assign to `*numero`, as `numero` is not declared as mutable
 --> boxx.rs:4:5
  |
3 |     let numero = Box::new(1);
  |         ------ help: consider changing this to be mutable: `mut numero`
4 |     *numero = 69;
  |     ^^^^^^^^^^^^ cannot assign

error: aborting due to previous error

For more information about this error, try `rustc --explain E0594`.

Declarando a variável como mutável podemos realizar essa alteração.

fn main() {
    let mut numero: Box<usize> = Box::new(42);
    *numero = 69;
    println!("{}", numero);
}

Tipos recursivos

Tipos recursivos, são aqueles que tem algum atributo que é representa ele mesmo. Como, por exemplo, em uma árvore binaria, cada "galho" é um tipo recursivo.

struct Galho {
    esquerda: Option<Galho>,
    direita: Option<Galho>,
    valor: usize,
}

fn main() {
    todo!();
}

Caso tentarmos compilar o código acima teremos o seguinte output do compilador:

error[E0072]: recursive type `Galho` has infinite size
 --> recursive.rs:2:1
  |
2 | struct Node {
  | ^^^^^^^^^^^ recursive type has infinite size
3 |     esquerda: Option<Galho>,
  |           ------------ recursive without indirection
4 |     direita: Option<Galho>,
  |            ------------ recursive without indirection
  |
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Node` representable
  |
3 ~     esquerda: Option<Box<Galho>>,
4 ~     direita: Option<Box<Galho>>,
  |

error: aborting due to previous error

For more information about this error, try `rustc --explain E0072`.

O próprio compilador já nos diz algo que podemos fazer para corrigir este problema, mas antes vamos entender o que seria essa mensagem aqui "recursive type has infinite size".

Teoricamente tipos recursivos podem crescer ao infinito e o compilador do Rust não sabe o quanto de memória sera necessário para esse tipo, por isso essa mensagem. Porém, ele sabe exatamente quanta memória é necessária para um Box, sendo possível a criação deste tipo recursivo utilizando esse Box.

struct Galho {
    esquerda: Option<Box<Galho>>,
    direita: Option<Box<Galho>>,
    valor: usize,
}

fn main() {
    todo!();
}

No livro Rust Book é possível ver um exemplo bem interessante utilizando uma Cons List.

Valores Dinâmicos

Recuperando o exemplo das traits de animais do capítulo sobre traits

Vamos supor que queremos ter uma lista de animais, sendo eles do tipo Cachorro, Gato e Papagaio. Podemos utilizar a palavra reservada dyn dentro de um Box<T>, para representar valores dinâmicos.

trait Animal {
    fn comer(&self);
}

struct Cachorro {}

impl Animal for Cachorro {
    fn comer(&self) {
        println!("Cachorro comendo...");
    }
}

struct Gato {}

impl Animal for Gato {
    fn comer(&self) {
        println!("gato comendo...");
    }
}

struct Papagaio {}

impl Animal for Papagaio {
    fn comer(&self) {
        println!("papagaio comendo...");
    }
}
fn main() {
    let animais: Vec<Box<dyn Animal>> = vec![
        Box::new(Gato {}),
        Box::new(Cachorro {}),
        Box::new(Papagaio {}),
    ];
    for animal in animais {
        animal.comer();
    }
}

Utilizando valores dinâmicos podemos ter tipos diferentes que implementam a mesma trait. Só devemos saber que, um ponteiro dinâmico ocupa o dobro do espaço que um ponteiro comum, isso por que temos um ponteiro para o tipo em questão e outro ponteiro para a implementação desta trait.