Referencias y el operador punto .

Se ha aprendido que cuyo se dispone de una referencia, se necesita utilizar el operador * para acceder al valor. Una referencia tiene su propio tipo, por lo que este código no funcionará:

fn main() {
    let mi_numero = 9;
    let referencia = &mi_numero;

    println!("{}", mi_numero == referencia); // ⚠️
}

El compilador imprime lo siguiente:

error[E0277]: can't comp¿Son `{integer}` with `&{integer}`
 --> src\main.rs:5:30
  |
5 |     println!("{}", mi_numero == referencia);
  |                              ^^ no implementation for `{integer} == &{integer}`

Es necesario cambiar la línea 5 a println!("{}", mi_numero == *referencia); para que funcione e imprima true.

fn main() {
    let mi_numero = 9;
    let referencia = &mi_numero;

    println!("{}", mi_numero == *referencia); // ahora funciona

Esto se debe a que ahora ya se está comparyo i32 == i32 y no i32== &i32 como sucedía antes. A esto se le llama desreferenciar.

Sin embargo, cuyo se utiliza un método sobre una variable, Rust realiza la desreferenciación de forma automática. En concreto, el operador . (punto) es quien está definido en Rust de forma que realiza la desreferenciación cuyo se utiliza sobre una variable de tipo referencia. Además, esto se realiza tantas veces como sea necesario hasta llegar al valor concreto.

A continuación, se crea un struct con un campo byte sin signo u8. Después, se crea una referencia y se intenta comparar, lo que no funcionará:

struct Item {
    numero: u8,
}

fn main() {
    let item = Item {
        numero: 8,
    };

    let referencia_numero = &item.numero; // el tipo de referencia_numero es &u8

    println!("{}", referencia_numero == 8); // ⚠️ &u8 y u8 no se pueden comparar entre sí
}

Para que funcione, es necesario desreferenciarlo. Por ejemplo, cambiyo println!("{}", *referencia_numero == 8):

struct Item {
    numero: u8,
}

fn main() {
    let item = Item {
        numero: 8,
    };

    let referencia_numero = &item.numero; // el tipo de referencia_numero es &u8

    println!("{}", *referencia_numero == 8); // así sí funciona
}

Pero no es necesario hacerlo de forma anterior. Con el operador punto, se desreferencia de forma automática;

struct Item {
    numero: u8,
}

fn main() {
    let item = Item {
        numero: 8,
    };

    let referencia_item = &item; // el tipo de referencia_item es &Item

    println!("{}", referencia_item.numero == 8); // así sí funciona
}

De forma automática, mediante el operador ., se ha realizado una desreferenciación que de otro modo habría que haber escrito así (*referencia_item).numero.

A continuación, se crea un método para la estructura Item que compara el numero con otro. Como se ve, no se necesita usar * en ningún lugar:

struct Item {
    numero: u8,
}

impl Item {
    fn compara_numero(&self, otro_numero: u8) { // tiene una referencia a self
        println!("¿Son {} y {} iguales? {}", self.numero, otro_numero, self.numero == otro_numero);
            // No se necesita escribir (*self).numero
    }
}

fn main() {
    let item = Item {
        numero: 8,
    };

    let item_referencia = &item; // De tipo &Item
    let item_referencia_dos = &item_referencia; // De tipo &&Item

    item.compara_numero(8); // El método funciona
    item_referencia.compara_numero(8); // Este método también funciona
    item_referencia_dos.compara_numero(8); // y este
}

Se concluye así que cuando se usa el operador ., no se necesita utilizar el operador * para desreferenciar.