Tipos de datos
Todo valor en Rust es de un tipo específico. Rust necesita saber ese tipo al momento de compilar el programa, y muchas veces puede inferir el tipo. En otras ocasiones debemos indicarlo explícitamente, y si no lo hacemos produciremos un error de compilación.
Hay dos categorías:
Escalares[edit]
Un tipo escalar representa un valor único, y existen cuatro tipos escalares: enteros, punto flotantes, booleanos, y caracteres.
Enteros[edit]
Un entero es un número sin una parte fraccional. Pueden tener signo o no, y ser de 8 a 128 bits. Si tiene signos, el tipo empieza con i y si no tiene signo empieza con u.
Tamaños y signo[edit]
El tipo empieza con i y u, y continúa con el tamaño en bits, desde 8 hasta 128 bits: i8, u8, i16, u16, y así sucesivamente hasta i128 y u128.
Se usa complemento a dos para representar los números negativos.
Punto flotante[edit]
Hay dos tipos primitivos de punto flotante: f32 (32 bits, precisión simple) y f64 (64 bits, doble precisión). Si no se especifica el tipo, se asume por defecto que es f64. Se usa el estándar IEEE-754 de punto flotante.
fn main(){
let pi = 3.14; // se asume tipo f64
let as: f32 = 3.14; // esta variable es de tipo f32
}
Booleanos[edit]
Una variable booleana puede ser o true o false, y ocupa un byte de almacenamiento.
fn main(){
let bandera = true;
let otra_bandera: bool = false;
}
Caracteres[edit]
Para almacenar letras, se puede usar char, y se define con comilla única (no doble comilla o comillas que son para las cadenas de caracteres). Los caracteres ocupan 4 bytes de almacenamiento.
fn main(){
let p = 'p';
}
Compuestos[edit]
Los tipos compuestos agrupan varios valores en un sólo tipo. Existen dos: tuples y arreglos.
Tuples[edit]
Agrupan diferentes tipos en un sólo tipo compuesto. Tienen un tamaño definido: no se pueden modificar de tamaño una vez creados.
Se crean usando paréntesis y separando la lista de valores con comas. Cada posición es un tipo, y no necesitan ser iguales.
fn main(){
let tuple: (i32, char) = (12,'d');
println!("El valor es {}",tuple.1);
}
La salida del programa sería d. (tuple.0 se refiere al i32, y tuple.1 al caracter).
Otra forma es asignar parte de ese tuple a una variable, de la siguiente manera:
fn main(){
let tuple: (i32, char) = (12,'d');
let (a,b)=tuple;
println!("El valor es {}",b);
}
Arreglos[edit]
En los arreglos, todos los valores deben ser del mismo tipo, y deben tener un tamaño fijo. En este ejemplo, el arreglo a tiene 3 valores:
fn main(){
let a = [0,1,2];
}
Los arreglos se definen estáticamente, por lo que están en el stack y no en el heap. Si se desea algo dinámico, se puede usar un vector.
Si se desea explicitar el tipo y el número de elemento se haría:
fn main(){
let a: [i32;3] = [0,1,2];
}
Si quieres inicializar todo un arreglo con un mismo valor puedes hacer esto:
fn main(){
let a = [5;10]; //esto inicializa con 10 elementos con un valor de 5.
}
Los elementos de un arreglo se accesan de la misma forma que en otros lenguajes: a[0] accesa su primer elemento, y así sucesivamente.
Arreglos bidimensionales[edit]
Se pueden definir explícitamente:
fn main(){
let mut state = [[0,0],[0,1]];
}
También se pueden definir de esta forma, un arreglo de 8 por 16:
fn main(){
let mut arreglo: [[i32; 16]; 8];
}
String[edit]
Un String está localizado en el heap y no en el stack, por lo que puede cambiar de tamaño durante la ejecución del programa. Se crea de la siguiente forma:
let s = String::from("hola");
Y se puede extender si le hacemos un push:
fn main() {
let mut s = String::from("hola");
s.push_str(", ¿cómo te va?");
println!("{}", s);
}
Este programa creará el String y le agregará al final el mensaje ", ¿cómo te va?".