Setters
Parte de la sección Object Oriented Programming del Journey de Rust de Coddy — lección 12 de 61.
Los getters permiten que el código externo lea datos privados. ¿Pero qué pasa si necesitas permitirles cambiarlo? Ahí es donde entran los métodos setter: métodos públicos que modifican campos privados de una manera controlada.
Un setter básico toma &mut self y un nuevo valor:
// wallet.rs
pub struct Wallet {
balance: f64,
}
impl Wallet {
pub fn new(initial: f64) -> Wallet {
Self { balance: initial }
}
pub fn balance(&self) -> f64 {
self.balance
}
pub fn set_balance(&mut self, amount: f64) {
self.balance = amount;
}
}
A diferencia de los getters, los setters en Rust suelen utilizar el prefijo set_ para indicar claramente que modifican datos. El parámetro &mut self es esencial: otorga al método permiso para cambiar los campos de la estructura.
El verdadero poder de los setters es la validación. En lugar de aceptar ciegamente cualquier valor, puedes imponer reglas:
pub fn set_balance(&mut self, amount: f64) {
if amount >= 0.0 {
self.balance = amount;
}
// Los valores negativos se ignoran silenciosamente
}
Ahora la billetera se protege a sí misma: sin importar qué valor intente establecer el código externo, el saldo nunca puede ser negativo. Esto es la encapsulación en acción: el struct controla sus propios invariantes y el código externo simplemente no puede ponerlo en un estado no válido.
Desafío
FácilVamos a construir un sistema de termostato que demuestre cómo los setters pueden aplicar reglas para mantener la validez de los datos. Tu termostato tendrá un ajuste de temperatura que solo se puede ajustar dentro de un rango seguro.
Crearás dos archivos para organizar tu código:
thermostat.rs: Define una estructuraThermostatcon un campo privadotemperature(i32). La estructura debe ser pública, pero el campo permanece privado para protegerlo de valores inválidos. Implementa:- Un constructor
newque reciba una temperatura inicial - Un getter
temperatureque devuelva la temperatura actual - Un setter
set_temperatureque solo acepte valores entre 10 y 30 (inclusive). Si el valor está fuera de este rango, la temperatura debe permanecer sin cambios.
- Un constructor
main.rs: Importa tu módulo de termostato, crea un termostato y demuestra la validación del setter intentando establecer varias temperaturas y imprimiendo el resultado después de cada intento.
El setter debe ignorar silenciosamente los valores inválidos; sin mensajes de error, simplemente mantén la temperatura actual sin cambios cuando alguien intente establecerla fuera del rango válido.
Tu salida debe seguir este formato exacto:
Initial: {temperature}
After setting to {attempted_value}: {temperature}
After setting to {attempted_value}: {temperature}Por ejemplo, si creas un termostato a 20, luego intentas establecerlo a 25 (válido) y después a 50 (inválido), la salida sería:
Initial: 20
After setting to 25: 25
After setting to 50: 25Recibirás tres entradas: la temperatura inicial, la primera temperatura a intentar y la segunda temperatura a intentar.
Hoja de referencia
Los métodos setter permiten que el código externo modifique campos privados de manera controlada. Toman &mut self para obtener permiso para cambiar los datos de la estructura.
Sintaxis básica de un setter:
pub fn set_balance(&mut self, amount: f64) {
self.balance = amount;
}Los setters en Rust suelen utilizar el prefijo set_ para indicar claramente que modifican datos.
Los setters permiten la validación para aplicar reglas y mantener la integridad de los datos:
pub fn set_balance(&mut self, amount: f64) {
if amount >= 0.0 {
self.balance = amount;
}
// Los valores no válidos se ignoran silenciosamente
}Esto es la encapsulación en acción: la estructura controla sus propios invariantes, evitando que el código externo la ponga en un estado no válido.
Pruébalo tú mismo
mod thermostat;
use thermostat::Thermostat;
fn main() {
// Leer las entradas
let mut input1 = String::new();
std::io::stdin().read_line(&mut input1).expect("Failed to read line");
let initial_temp: i32 = input1.trim().parse().expect("Invalid number");
let mut input2 = String::new();
std::io::stdin().read_line(&mut input2).expect("Failed to read line");
let first_attempt: i32 = input2.trim().parse().expect("Invalid number");
let mut input3 = String::new();
std::io::stdin().read_line(&mut input3).expect("Failed to read line");
let second_attempt: i32 = input3.trim().parse().expect("Invalid number");
// TODO: Crear un termostato con la temperatura inicial
// TODO: Imprimir la temperatura inicial
// Formato: "Initial: {temperature}"
// TODO: Intentar establecer la primera temperatura e imprimir el resultado
// Formato: "After setting to {attempted_value}: {temperature}"
// TODO: Intentar establecer la segunda temperatura e imprimir el resultado
// Formato: "After setting to {attempted_value}: {temperature}"
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Object Oriented Programming
1Métodos y Comportamiento
Intro a Bloques de ImplementaciónEl Parámetro SelfMétodos MutablesFunciones AsociadasMúltiples Bloques de ImplementaciónEncadenamiento de MétodosResumen - Acciones de Rectángulo4Proyecto: Mascota virtual
Definir la mascotaAlimentar a la mascota7Traits estándar
El trait DebugEl trait DisplayClone y CopyTraits de igualdadResumen - Punto imprimible10Proyecto: Sistema de documentos
El Trait DrawComponente de texto2Encapsulamiento y módulos
Conceptos básicos de módulosLa palabra clave PublicCampos privadosGettersSettersRepaso - Casillero seguro5Genéricos
Estructuras genéricasMétodos genéricosMúltiples tipos genéricosFunciones genéricasResumen - Punto de coordenadas8Traits como límites
Sintaxis de límites de traitsLímites múltiplesLa cláusula whereRetornar tipos con traitsResumen: Impresora genérica11Patrones de diseño en Rust
Patrón NewtypeComposiciónEl Trait DropFrom e IntoResumen - Mock de Smart Pointer3Enums avanzados
Enums con datosMétodos en EnumsCoincidencia de variantes de datosEl Enum Option revisitadoResumen - Enum Shape6Definición de Traits
¿Qué es un Trait?Implementación de TraitsImplementaciones por defectoSobrescribir valores por defectoTraits con parámetrosResumen - Reproductor multimedia