Campos privados
Parte de la sección Programación Orientada a Objetos del Journey de Rust de Coddy. Lección 10 de 61.
En la lección anterior, hiciste todo público: la estructura, sus campos y sus métodos. Pero la verdadera encapsulación significa controlar cómo se puede acceder a tus datos. En Rust, puedes hacer pública una estructura mientras mantienes privados sus campos.
Considera una Wallet que nunca debería tener un saldo negativo. Si el campo es público, cualquiera podría asignarle cualquier valor:
// wallet.rs
pub struct Wallet {
balance: f64, // ¡Sin pub = privado!
}
impl Wallet {
pub fn new(initial: f64) -> Wallet {
Wallet { balance: initial }
}
}
Observa que Wallet es público, pero balance no tiene la palabra clave pub. Esto significa que el código fuera del módulo puede crear un Wallet usando el constructor, pero no puede leer ni modificar directamente el campo balance:
// main.rs
mod wallet;
use wallet::Wallet;
fn main() {
let w = Wallet::new(100.0);
// println!("{}", w.balance); // ¡Error! el campo es privado
// w.balance = -50.0; // ¡Error! no se puede acceder al campo privado
}
Esta es la base de la encapsulación: la estructura controla sus propios datos. El código externo debe pasar por los métodos que proporcionas, lo que significa que puedes añadir validación, registro u otra lógica. Los datos permanecen protegidos frente a estados no válidos.
En las próximas lecciones, aprenderás a proporcionar un acceso controlado a estos datos privados mediante métodos getter y setter.
Desafío
FácilConstruyamos un sistema de sensor de temperatura que demuestre la encapsulación manteniendo los datos sensibles protegidos dentro de un módulo.
Crearás dos archivos para organizar tu código:
sensor.rs: Define una estructuraTemperatureSensorcon dos campos:location(String) yreading(f64). La estructura debe ser pública para que pueda usarse desde otros archivos, pero mantén ambos campos privados: el código externo no debería poder acceder directamente a los datos del sensor ni modificarlos. Añade un constructor públiconewque reciba un nombre de ubicación y una lectura de temperatura inicial.main.rs: Incluye tu módulo de sensor y crea unTemperatureSensorusando el constructor. Como los campos son privados, no podrás imprimirlos directamente; en su lugar, imprime un mensaje de confirmación que muestre que el sensor se creó correctamente.
Este desafío se centra en el concepto fundamental de los campos privados: se puede acceder a la estructura, pero sus datos internos están protegidos. El código externo solo puede interactuar con el sensor mediante los métodos que proporciones (en este caso, únicamente el constructor).
Tu salida debe seguir exactamente este formato:
Sensor created for: {location}Para acceder a la ubicación al imprimirla, tendrás que hacer que tu función new imprima este mensaje antes de devolver el sensor, ya que el campo en sí es privado.
Por ejemplo, si creas un sensor con la ubicación "Kitchen" y la lectura 22.5, la salida sería:
Sensor created for: KitchenRecibirás dos entradas: el nombre de la ubicación y la lectura de temperatura inicial.
REQUIRED OUTPUT FORMAT:Pruébalo tú mismo
mod sensor;
use sensor::TemperatureSensor;
fn main() {
// Leer entrada
let mut location = String::new();
std::io::stdin().read_line(&mut location).expect("Failed to read line");
let location = location.trim().to_string();
let mut reading_str = String::new();
std::io::stdin().read_line(&mut reading_str).expect("Failed to read line");
let reading: f64 = reading_str.trim().parse().expect("Failed to parse reading");
// TODO: Crea un TemperatureSensor usando el constructor
// La función new se encargará de imprimir el mensaje de confirmación
}
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