En Rust, asignar un valor a un nombre se conoce como un enlace. Los enlaces son inmutables a menos que se declaren con la palabra clave mut. Como Rust es un lenguaje de tipado estático, cada enlace tiene un tipo conocido en tiempo de compilación.
Los enlaces se definen casi siempre con la palabra clave let. Especificar el tipo de un enlace es opcional para la mayoría de los enlaces, ya que la inferencia de tipos de Rust normalmente puede deducir el tipo a partir de su valor. Un enlace se ve así:
// Automatically inferred type
let fingers = 10;
Las funciones son elementos. Mientras que los enlaces normalmente se refieren a un valor concreto, los elementos se refieren a una unidad de organización del código, normalmente una función o un módulo, que está disponible durante toda la vida del programa. Una función devuelve automáticamente el resultado de su última expresión. Una función puede tener 0 o más parámetros, que son enlaces con un tiempo de vida igual al de la llamada a la función.
La inferencia de tipos es teóricamente posible para las funciones, pero está deshabilitada como una decisión intencional de diseño del lenguaje. Aunque esto significa que necesitas dedicar un poco más de tiempo al escribir el código para especificar con precisión cuáles son los tipos de entrada y salida de una función, ese tiempo lo ahorras al leer el código, porque todos los tipos de entrada y salida están definidos explícitamente.
fn add(x: i32, y: i32) -> i32 {
x + y
}
Para invocar una función, escribes su nombre y después unos paréntesis. Si la función requiere parámetros, debes especificar un argumento para cada uno dentro de los paréntesis.
let five = add(2, 3);
Si el tipo de un enlace no se puede inferir, el compilador reportará un error. Para solucionarlo, agrega una anotación de tipo explícita al enlace.
// Explicit type annotation
let fingers: i32 = 10;
Los elementos en Rust se pueden usar antes o después de definirse, porque tienen un tiempo de vida estático. Los enlaces, en cambio, solo se pueden usar después de haberse definido. Usar un enlace antes de definirlo da como resultado un error de compilación.
fn main() {
// `fn add` hasn't yet been defined, but that's perfectly ok
dbg!(add(3, 4));
}
fn add(x: i32, y: i32) -> i32 {
x + y
}
// this won't compile; `a` is used before its binding is defined
let b = a;
let a = x + y;
Rust usa llaves ({}) para definir un ámbito. Un enlace definido dentro de un ámbito no puede escapar de él.
let a = 1;
dbg!(a); // 1
{
// Here, we re-bind `a` to a new value, which is still immutable.
// This technique is called _shadowing_. The new binding is constrained to
// this anonymous scope. Outside this scope, the previous binding still
// applies.
let a = 2;
let b = 3;
dbg!(a, b); // 2, 3
}
// can't use `b` anymore because it is out of scope
// dbg!(b);
// The shadowed `a` in the inner scope above has fallen out of scope,
// leaving us with our original binding.
dbg!(a); // 1
Los elementos de Rust suelen organizarse en módulos. Cada crate es implícitamente un módulo, pero puede definir submódulos internos de profundidad arbitraria. Un módulo agrupa funcionalidad relacionada y se define con la palabra clave mod.
mod calc_i32 {
fn add(a: i32, b: i32) -> i32 { a + b }
fn sub(a: i32, b: i32) -> i32 { a - b }
fn mul(a: i32, b: i32) -> i32 { a * b }
fn div(a: i32, b: i32) -> i32 { a / b }
}
Rust admite dos tipos de comentarios. La palabra clave // indica un comentario de una sola línea; todo lo que sigue a la palabra clave hasta el final de la línea se ignora. Las palabras clave /* y */ indican un comentario de varias líneas; todo lo que está dentro de esas dos palabras clave se ignora. Es idiomático y una buena práctica preferir los comentarios de una sola línea.
Rust también admite comentarios de documentación, que aparecen en la documentación generada por cargo doc. Los comentarios de documentación externos se forman con la palabra clave ///, que actúa de forma idéntica a la palabra clave //. Se aplican al elemento que los sigue, como una función:
/// The `add` function produces the sum of its arguments.
fn add(x: i32, y: i32) -> i32 { x + y }
Los comentarios de documentación internos se forman con la palabra clave //!, que actúa de forma idéntica a la palabra clave //. Se aplican al elemento que los contiene, como un módulo:
mod my_cool_module {
//! This module is the bee's knees.
}
Los comentarios de documentación pueden tener cualquier longitud y contener markdown, que se renderiza en la documentación generada.
En este ejercicio vas a escribir un poco de código para ayudarte a cocinar una lasaña espectacular del libro de cocina que más te gusta.
Tienes cuatro tareas, todas relacionadas con el tiempo que se dedica a cocinar la lasaña.
Define el binding expected_minutes_in_oven para comprobar cuántos minutos debe estar la lasaña en el horno. Según el libro de cocina, el tiempo esperado en el horno en minutos es 40:
expected_minutes_in_oven()
// Returns: 40
Define la función remaining_minutes_in_oven que toma como parámetro los minutos reales que la lasaña ha estado en el horno y devuelve cuántos minutos le queda por estar en el horno, según el tiempo esperado en el horno en minutos de la tarea anterior.
remaining_minutes_in_oven(30)
// Returns: 10
Define la función preparation_time_in_minutes que toma como parámetro el número de capas que le agregaste a la lasaña y devuelve cuántos minutos dedicaste a prepararla, suponiendo que cada capa te toma 2 minutos preparar.
preparation_time_in_minutes(2)
// Returns: 4
Define la función elapsed_time_in_minutes que toma dos parámetros: el primer parámetro es el número de capas que le agregaste a la lasaña, y el segundo parámetro es el número de minutos que la lasaña ha estado en el horno. La función debe devolver cuántos minutos has dedicado a cocinar la lasaña, que es la suma del tiempo de preparación en minutos y el tiempo en minutos que la lasaña ha pasado en el horno hasta el momento.
elapsed_time_in_minutes(3, 20)
// Returns: 26
Regístrate en Exercism para aprender y dominar Rust con 99 ejercicios y mentoría humana real, todo gratis.