El primer tema de este tutorial vimos un tipo de dato definido por el usuario, es conocido desde hace mucho tiempo por los programadores en otros lenguajes como tipos de suma, uniones discriminadas o tipos de datos algebraicos. En Rust, se les llama enumeraciones o simplemente enums
. A diferencia de otros lenguajes, son bastante seguros y el precio que piden no supone una gran privación.
C++ y C# tienen enumeraciones o enums
; puedes usarlas para definir tu propio tipo cuyos valores son un conjunto de constantes con nombre. Por ejemplo, podrías definir un tipo llamado Color con valores Rojo, Naranja, Amarillo, y así sucesivamente. Este tipo de enumeración también funciona en Rust. Pero Rust lleva las enumeraciones mucho más lejos. Una enumeración en Rust también puede contener datos, incluso datos de tipos diferentes.
Por ejemplo, el tipo Result<String
, io::Error>
de Rust es una enumeración; dicho valor es o bien un valor Ok
que contiene un String
o un valor Err
que contiene un io::Error
. Esto va más allá de lo que las enumeraciones de C++ y C# pueden hacer. Es más parecido a las union
en C, pero a diferencia de las union
, las enumeraciones o enums
de Rust son seguras en cuanto a tipos.
Las enumeraciones son útiles siempre que un valor pueda ser una cosa u otra. El "precio" de usarlas es que debes acceder a los datos de forma segura, utilizando el pattern matching
, nuestro tema para la segunda mitad de este tutorial.
Los patrones patterns
también pueden resultarte familiares si has utilizado la desempaquetación en Python o la destructuración en JavaScript, pero Rust lleva los patrones más lejos. Los patrones en Rust son un poco como expresiones regulares para todos tus datos. Se utilizan para probar si un valor tiene o no una forma deseada en particular. Pueden extraer varios campos de una estructura o tupla en variables locales a la vez. Y al igual que las expresiones regulares, son concisos, generalmente haciéndolo todo en una sola línea de código.
Este sección comienza con lo básico de las enumeraciones, mostrando cómo se pueden asociar datos con las variantes de una enumeración y cómo se almacenan las enumeraciones en la memoria.
Luego mostraremos cómo los patrones o patterns
y las declaraciones de coincidencia o match
de Rust pueden especificar de manera concisa la lógica basada en enumeraciones o enums, structs, arrays y slices
.
Los patrones también pueden incluir referencias, movimientos o move
y condiciones if
, lo que los hace aún más capaces.
Las enumeraciones simples al estilo C son directas:
enum Ordering {
Less,
Equal,
Greater,
}
Esto declara un tipo llamado "Ordering
" con tres posibles valores, llamados variantes o constructores: Ordering::Less
, Ordering::Equal
y Ordering::Greater
. Esta enumeración en particular es parte de la biblioteca estándar, por lo que el código de Rust puede importarla, ya sea por sí misma:
use std::cmp::Ordering;
fn compare(n: i32, m: i32) -> Ordering {
if n < m {
Ordering::Less
} else if n > m {
Ordering::Greater
} else {
Ordering::Equal
}
}
o con todos sus constructores:
use std::cmp::Ordering::{self, *};
// `*` to import all children
fn compare(n: i32, m: i32) -> Ordering {
if n < m {
Less
} else if n > m {
Greater
} else {
Equal
}
}
Después de importar los constructores, podemos escribir "Less
" en lugar de "Ordering::Less
", y así sucesivamente. Sin embargo, debido a que esto es menos explícito, generalmente se considera un mejor estilo no importarlos excepto cuando hace que tu código sea mucho más legible.
Para importar los constructores de una enumeración declarada en el módulo actual, utiliza una importación "self
":
enum Pet {
Orca,
Giraffe,
...
}
// import constructors
use self::Pet::*;
En memoria, los valores de las enumeraciones al estilo C se almacenan como enteros. Ocasionalmente, es útil indicarle a Rust qué enteros utilizar:
enum HttpStatus {
Ok = 200,
NotModified = 304,
NotFound = 404,
...
}
De lo contrario, Rust asignará los números por ti, comenzando desde 0. Por defecto, Rust almacena las enumeraciones al estilo C utilizando el tipo entero incorporado más pequeño que pueda acomodarlas. La mayoría caben en un solo byte: