Setters
Parte de la sección Programación Orientada a Objetos del Journey de Rust de Coddy. Lección 12 de 61.
Los getters permiten que el código externo lea datos privados. Pero ¿qué ocurre si necesitas permitirle cambiarlos? Ahí es donde entran los métodos setter: métodos públicos que modifican campos privados de forma controlada.
Un setter básico acepta &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 de Rust suelen usar el prefijo set_ para indicar claramente que modifican datos. El parámetro &mut self es esencial. Concede 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 hacer cumplir 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: la estructura controla sus propias invariantes, y el código externo simplemente no puede hacer que adopte un estado no válido.
Desafío
FácilConstruyamos un sistema de termostato que demuestre cómo los setters pueden aplicar reglas para mantener los datos válidos. Tu termostato tendrá un ajuste de temperatura que solo se podrá modificar dentro de un rango seguro.
Crearás dos archivos para organizar tu código:
thermostat.rs: Define una estructuraThermostatcon un campotemperatureprivado (i32). La estructura debe ser pública, pero el campo debe permanecer privado para protegerlo de valores no vá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: Incluye tu módulo del termostato, crea un termostato y demuestra la validación del setter intentando establecer varias temperaturas e imprimiendo el resultado después de cada intento.
El setter debe ignorar silenciosamente los valores no válidos: sin mensajes de error, simplemente debe mantener la temperatura actual sin cambios cuando alguien intente establecerla fuera del rango válido.
Tu salida debe seguir exactamente este formato:
Initial: {temperature}
After setting to {attempted_value}: {temperature}
After setting to {attempted_value}: {temperature}Por ejemplo, si creas un termostato a 20, después intentas establecerlo en 25 (válido) y después en 50 (no vá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 que se intentará establecer y la segunda temperatura que se intentará establecer.
Pruébalo tú mismo
mod thermostat;
use thermostat::Thermostat;
fn main() {
// Leer 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: Crea un termostato con la temperatura inicial
// TODO: Imprime la temperatura inicial
// Formato: "Initial: {temperature}"
// TODO: Intenta establecer la primera temperatura e imprime el resultado
// Format: "After setting to {attempted_value}: {temperature}"
// TODO: Intenta establecer la segunda temperatura e imprime el resultado
// Format: "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 Programación Orientada a Objetos
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 multimediaPractica por tu cuenta: Compilador de Rust online