Funciones: recibir un valor y devolver un resultado
Lee una firma, pasa un argumento y usa el resultado de una función. Relaciona el tipo de retorno con la expresión final del bloque.
Ya puedes ejecutar un programa y declarar valores. Ahora necesitas separar una operación para usarla con entradas distintas. Una función tiene un nombre, puede recibir parámetros y puede devolver un resultado al código que la llama.
Sigue una llamada
fn conservar_numero(numero: i32) -> i32 { numero}fn main() { let entrada = 12; let resultado = conservar_numero(entrada); println!("Resultado: {resultado}");}Antes de ejecutar, predice la salida. La llamada entrega el valor 12 al parámetro numero. La expresión final del cuerpo produce ese número y la llamada devuelve 12; el llamador lo guarda en resultado.
En la firma, numero: i32 declara el nombre y el tipo del parámetro. El -> i32 declara el tipo del resultado. En la llamada, entrada es el argumento: la expresión que proporciona el valor recibido.
Aquí usamos un entero, que es Copy. Más adelante, al trabajar con String, tendrás que seguir también si una llamada transfiere propiedad o toma prestado el dato. No deduzcas de este ejemplo que todos los valores se copian al pasar a una función.
Devuelve una respuesta
Una función puede calcular un resultado de otro tipo:
fn es_cero(numero: i32) -> bool { numero == 0}fn main() { let primero = es_cero(8); let segundo = es_cero(0); println!("{primero} y {segundo}");}== compara los valores y produce un booleano: true si son iguales y false si son distintos. La firma recibe un entero y devuelve bool, de acuerdo con esa operación. El programa imprime false y true.
Cambiar una función exige conservar su contrato. Para es_cero, el contrato es devolver true exactamente cuando la entrada sea cero. Prueba también un número negativo: reconocer un caso positivo no basta para distinguir todas las implementaciones incorrectas.
La expresión final del bloque
En estos ejemplos el resultado es la expresión final sin punto y coma. Si añades ;, la expresión pasa a ser una sentencia y ese bloque deja de producir el booleano requerido:
fn es_cero(numero: i32) -> bool { numero == 0;}fn main() { println!("{}", es_cero(0));}Este ejemplo falla con E0308. El cuerpo produce (), el tipo unit, mientras la firma exige bool. Localiza esos dos tipos en el diagnóstico y quita el punto y coma para devolver el resultado de la comparación. La lección de bloques profundiza en este comportamiento; aquí basta con conectar cuerpo y firma.
Usa un bloque para obtener un resultado
fn conservar_numero(numero: i32) -> i32 { let resultado = { let temporal = numero; temporal }; resultado}fn main() { println!("{}", conservar_numero(-4));}El bloque interior produce temporal, y ese valor inicializa resultado. El punto y coma después de la llave termina la declaración let resultado = ...;; no elimina el valor que produjo el bloque interior. La expresión final de la función devuelve después resultado.
Esta estructura prepara las transferencias entre bloques. En la práctica con String el valor podrá cambiar de dueño al salir del bloque; el mecanismo de expresión final seguirá siendo el mismo.
Comprueba lo que puedes hacer
- Cambia la entrada de
conservar_numeroy predice su resultado antes de ejecutar. - Comprueba
es_cerocon cero, un positivo y un negativo. Escribe qué resultado exige el contrato para cada entrada. - Introduce y corrige el error del punto y coma, localizando la diferencia entre el tipo esperado y el producido.
- Escribe
fn son_iguales(izquierda: i32, derecha: i32) -> bool. Comprueba una pareja igual y otra distinta. Los parámetros se separan con una coma.
Puedes consultar la sintaxis mientras resuelves. La capacidad que buscas es conectar entrada, operación y resultado. Estas tareas son práctica manual; la lectura todavía no tiene un evaluador que registre evidencia.
Para consultar: Funciones en The Rust Programming Language.