Búsqueda de sitios web

Serie de conceptos básicos de Rust n.° 3: tipos de datos en Rust


En el tercer capítulo de esta serie, aprenderá sobre los tipos de datos enteros, flotantes, caracteres y booleanos en el lenguaje de programación Rust.

En la publicación anterior sobre el lenguaje de programación Rust, analizamos variables, constantes y sombreado.

Ahora es natural cubrir los tipos de datos.

¿Qué son los tipos de datos?

Cambia el orden de estas palabras y obtendrás tu respuesta; "tipos de datos" -> "tipo de datos".

La computadora almacena datos como 0s y 1s, pero para que tengan sentido al leerlos, usamos el tipo de datos para decir qué son esos 0s. y 1s significan.

Rust tiene dos tipos de tipos de datos:

  1. Tipo de datos escalar: tipos que almacenan un solo valor.

  2. Tipo de datos compuestos: tipos que almacenan múltiples valores, incluso valores de diferentes tipos.

En este artículo, cubriré los tipos de datos escalares. Revisaré la segunda categoría en el próximo artículo.

A continuación se muestra una breve descripción general de las cuatro categorías principales de tipos de datos escalares en Rust:

  • Enteros: almacena números enteros. Tiene subtipos para cada caso de uso específico.

  • Flotadores: almacena números con un valor fraccionario. Tiene dos subtipos según el tamaño.

  • Caracteres: almacena un solo carácter de codificación UTF-8. (Sí, puedes almacenar un emoji* en un carácter).

  • Booleanos: almacena un true o un false. (Para desarrolladores que no pueden ponerse de acuerdo si 0 es true o si 0 significa false).

Enteros

Un número entero en el contexto de un lenguaje de programación se refiere a números enteros. Los enteros en Rust están firmados o sin firmar. Los enteros sin signo almacenan solo 0 y números positivos, mientras que los enteros con signo pueden almacenar números negativos, 0 y números positivos.

El rango de enteros con signo comienza desde -(2n-1) y este rango termina con (2n-1)- 1. Del mismo modo, el rango de enteros sin signo comienza en 0 y termina en (2n)-1.

Los siguientes son los tipos de enteros disponibles según el signo y la longitud:

Como puede ver, Rust tiene enteros con y sin signo de longitud 8, 16, 32, 64 e incluso 128.

Los números enteros con *size varían según la arquitectura de la computadora. En microcontroladores de 8 bits, es *8, en computadoras heredadas de 32 bits, es *32 y en sistemas modernos de 64 bits, es *64.

El uso de *size es para almacenar datos que están relacionados principalmente con la memoria (que depende de la máquina), como punteros, compensaciones, etc.

Cuando no especifica explícitamente un subconjunto del tipo Integer, el compilador de Rust inferirá que su tipo es i32 de forma predeterminada. Obviamente, si el valor es mayor o menor que lo que i32 puede contener, el compilador de Rust generará un error cortésmente y le pedirá que anote manualmente el tipo.

Rust no sólo te permite almacenar números enteros en su forma decimal, sino también en forma binaria, octal y hexadecimal.

Para una mejor legibilidad, puede utilizar el guión bajo _ como reemplazo de las comas al escribir/leer números grandes.

fn main() {
    let bin_value = 0b100_0101; // use prefix '0b' for Binary representation
    let oct_value = 0o105; // use prefix '0o' for Octals
    let hex_value = 0x45; // use prefix '0x' for Hexadecimals
    let dec_value = 1_00_00_000; // same as writing 1 Crore (1,00,00,000)

    println!("bin_value: {bin_value}");
    println!("oct_value: {oct_value}");
    println!("hex_value: {hex_value}");
    println!("dec_value: {dec_value}");
}

He almacenado el número decimal 69 en forma binaria, forma octal y forma hexadecimal en las variables bin_value, oct_value y hex_value respectivamente. En la variable dec_value, almacené el número 1 crore (10 millones) y tengo comas con guiones bajos, según el sistema de numeración indio. Para aquellos más familiarizados con el sistema de numeración internacional, pueden escribir esto como 10_000_000.

Al compilar y ejecutar este binario, obtengo el siguiente resultado:

bin_value: 69
oct_value: 69
hex_value: 69
dec_value: 10000000

Números de punto flotante

Los números de punto flotante, o más comúnmente conocidos como "flotantes", son un tipo de datos que contienen números que tienen un valor fraccionario (algo después del punto decimal).

A diferencia del tipo entero en Rust, los números de coma flotante solo tienen dos tipos de subconjuntos:

  • f32: tipo de punto flotante de precisión simple

  • f64: tipo de coma flotante de doble precisión

Al igual que el tipo Integer en Rust, cuando Rust infiere el tipo de una variable que parece flotante, se le asigna el tipo f64. Esto se debe a que el tipo f64 tiene más precisión que el tipo f32 y es casi tan rápido como el tipo f32 en la mayoría de las operaciones computacionales. Tenga en cuenta que ambos tipos de datos de punto flotante (f32 y f64) están firmados.

El lenguaje de programación Rust almacena los números de punto flotante según el estándar IEEE 754 de representación y aritmética de números de punto flotante.

fn main() {
    let pi: f32 = 3.1400; // f32
    let golden_ratio = 1.610000; // f64
    let five = 5.00; // decimal point indicates that it must be inferred as a float
    let six: f64 = 6.; // even the though type is annotated, a decimal point is still
                       // **necessary**

    println!("pi: {pi}");
    println!("golden_ratio: {golden_ratio}");
    println!("five: {five}");
    println!("six: {six}");
}

Mire de cerca la quinta línea. Aunque he anotado el tipo de la variable six, necesitoal menos usar el punto decimal. Si tiene algo después del punto decimal, depende de usted.

El resultado de este programa es bastante predecible... ¿O no?

pi: 3.14
golden_ratio: 1.61
five: 5
six: 6

En el resultado anterior, es posible que hayas notado que mientras se muestra el valor almacenado dentro de las variables pi, golden_ratio y five, los ceros finales que especifiqué en el momento de la declaración de la variable, faltan.

Si bien esos ceros no se eliminan, se omiten al generar los valores a través de la macro println. Entonces no, Rust no manipuló los valores de su variable.

Caracteres

Puede almacenar un solo carácter en una variable y el tipo es simplemente char. Al igual que los lenguajes de programación tradicionales de los años 80, puedes almacenar un carácter ASCII. Pero Rust también amplía el tipo de carácter para almacenar un carácter UTF-8 válido. Esto significa que puedes almacenar un emoji en un solo carácter 😉

Algunos emojis son una mezcla de dos emojis existentes. Un buen ejemplo es el emoji 'Corazón ardiente': ❤️🔥. Este emoji se construye combinando dos emojis usando una unión de ancho cero: ❤️ + 🔥=❤️🔥

No es posible almacenar dichos emojis en una única variable Rust del tipo de carácter.

fn main() {
    let a = 'a';
    let p: char = 'p'; // with explicit type annotation
    let crab = '🦀';

    println!("Oh look, {} {}! :{}", a, crab, p);
}

Como puede ver, he almacenado los caracteres ASCII 'a' y 'p' dentro de las variables a y p. También almaceno un carácter UTF-8 válido, el emoji de cangrejo, en la variable cangrejo. Luego imprimo los caracteres almacenados en cada una de estas variables.

El siguiente es el resultado:

Oh look, a 🦀! :p

Booleanos

El tipo booleano en Rust almacena solo uno de dos valores posibles: true o false. Si desea anotar el tipo, utilice bool para indicar el tipo.

fn main() {
    let val_t: bool = true;
    let val_f = false;

    println!("val_t: {val_t}");
    println!("val_f: {val_f}");
}

El código anterior, cuando se compila y ejecuta, da como resultado el siguiente resultado:

val_t: true
val_f: false

Bonificación: encasillamiento explícito

En el artículo anterior sobre Variables en el lenguaje de programación Rust, mostré un programa de conversión de temperatura muy básico. Allí, mencioné que Rust no permite el encasillamiento implícito.

Pero eso no significa que Rust tampoco permita el encasillamiento explícito;)

Para realizar una conversión de tipos explícita, se utiliza la palabra clave as seguida del tipo de datos al que se debe convertir el valor.

A continuación se muestra un programa de demostración:

fn main() {
    let a = 3 as f64; // f64
    let b = 3.14159265359 as i32; // i32

    println!("a: {a}");
    println!("b: {b}");
}

En la línea 2, en lugar de usar '3.0', sigo el '3' con as f64 para indicar que quiero que el compilador maneje la conversión de tipos de '3' (un entero) en un formato 64- poco flotante. Lo mismo ocurre con la tercera línea. Pero aquí, la conversión de tipos es con pérdidas. Es decir, que el elemento fraccionario ha desaparecido por completo. En lugar de almacenar 3.14159265359, se almacena simplemente como 3.

Esto se puede verificar en la salida del programa:

a: 3
b: 3

Conclusión

Este artículo cubre los tipos de datos primitivos/escalares en Rust. Existen principalmente cuatro tipos de datos de este tipo: enteros, números de coma flotante, caracteres y booleanos.

Los números enteros se utilizan para almacenar números enteros y tienen varios subtipos según estén con o sin signo y la longitud. Los números de coma flotante se utilizan para almacenar números con algunos valores fraccionarios y tienen dos subtipos según la longitud. El tipo de datos de carácter se utiliza para almacenar un único carácter codificado en UTF-8 válido. Finalmente, los valores booleanos se utilizan para almacenar un valor true o false.

En el próximo capítulo, analizo tipos de datos compuestos como matrices y tuplas.

Manténganse al tanto.