lunes, 3 de julio de 2023

Rust: Conversiones implícitas


Rust no aplicará automáticamente conversiones implícitas entre tipos (a diferencia de C++). Puedes ver esto en un programa como este:

fn multiply(x: i16, y: i16) -> i16 {

    x * y

}

fn main() {

    let x: i8 = 15;

    let y: i16 = 1000;

    println!("{x} * {y} = {}", multiply(x, y));

}


Si corremos este código: 

$ cargo run

   Compiling hello_cargo v0.1.0 

error[E0308]: mismatched types

 --> src/main.rs:9:41

  |

9 |     println!("{x} * {y} = {}", multiply(x, y));

  |                                -------- ^ expected `i16`, found `i8`

  |                                |

  |                                arguments to this function are incorrect

  |

note: function defined here

 --> src/main.rs:1:4

  |

1 | fn multiply(x: i16, y: i16) -> i16 {

  |    ^^^^^^^^ ------

help: you can convert an `i8` to an `i16`

  |

9 |     println!("{x} * {y} = {}", multiply(x.into(), y));

  |                                          +++++++


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

error: could not compile `hello_cargo` due to previous error


Vamos a hacerle caso y vamos a correr : rustc --explain E0308


El tipo esperado no coincide con el tipo recibido.


Ejemplos de código erróneo:

``

fn plus_one(x: i32) -> i32 {

    x + 1

}


plus_one("Not a number");

//       ^^^^^^^^^^^^^^ expected `i32`, found `&str`


if "Not a bool" {

// ^^^^^^^^^^^^ expected `bool`, found `&str`

}


let x: f32 = "Not a float";

//     ---   ^^^^^^^^^^^^^ expected `f32`, found `&str`

//     |

//     expected due to this

```

Este error ocurre cuando se usó una expresión en un lugar donde el compilador esperaba una expresión de un tipo diferente. Puede ocurrir en varios casos, siendo el más común cuando se llama a una función y se pasa un argumento que tiene un tipo diferente al tipo coincidente en la declaración de la función.


Genial! no cambio el tipo de forma implicita. 

Todos los tipos enteros de Rust implementan las características From<T> e Into<T> para permitirnos convertir entre ellos. El rasgo From<T> tiene un solo método from() y, de manera similar, el rasgo Into<T> tiene un solo método into(). La implementación de estos rasgos es la forma en que un tipo expresa que se puede convertir en otro tipo.

La biblioteca estándar tiene una implementación de From<i8> para i16, lo que significa que podemos convertir una variable x de tipo i8 en i16 llamando a i16::from(x). O, más simple, con x.into(), porque From<i8> para la implementación de i16 crea automáticamente una implementación de Into<i16> para i8.

Lo mismo se aplica a sus propias implementaciones From para sus propios tipos, por lo que es suficiente implementar solo From para obtener una implementación Into respectiva automáticamente.

Por lo tanto si hacemos .into() este código va funcionar : 


fn multiply(x: i16, y: i16) -> i16 {

    x * y

}


fn main() {

    let x: i8 = 15;

    let y: i16 = 1000;

    println!("{x} * {y} = {}", multiply(x.into(), y));

}


$ cargo run

   Compiling hello_cargo v0.1.0 

    Finished dev [unoptimized + debuginfo] target(s) in 0.83s

     Running `target/debug/hello_cargo`

15 * 1000 = 15000


No hay comentarios.:

Publicar un comentario