Campos Privados
Parte da seção Object Oriented Programming do Journey de Rust da Coddy — lição 10 de 61.
Na lição anterior, você tornou tudo público—a struct, seus campos e seus métodos. Mas o verdadeiro encapsulamento significa controlar como seus dados podem ser acessados. Em Rust, você pode tornar uma struct pública enquanto mantém seus campos privados.
Considere uma Wallet que nunca deve ter um saldo negativo. Se o campo for público, qualquer pessoa poderia defini-lo para qualquer valor:
// wallet.rs
pub struct Wallet {
balance: f64, // Sem pub = privado!
}
impl Wallet {
pub fn new(initial: f64) -> Wallet {
Wallet { balance: initial }
}
}
Observe que Wallet é pública, mas balance não possui a palavra-chave pub. Isso significa que o código fora do módulo pode criar uma Wallet usando o construtor, mas não pode ler ou modificar diretamente o campo balance:
// main.rs
mod wallet;
use wallet::Wallet;
fn main() {
let w = Wallet::new(100.0);
// println!("{}", w.balance); // Erro! o campo é privado
// w.balance = -50.0; // Erro! não é possível acessar o campo privado
}
Este é o fundamento do encapsulamento — a struct controla seus próprios dados. O código externo deve passar pelos métodos que você fornece, o que significa que você pode adicionar validação, log ou qualquer outra lógica. Os dados permanecem protegidos contra estados inválidos.
Nas próximas lições, você aprenderá como fornecer acesso controlado a esses dados privados através de métodos getter e setter.
Desafio
FácilVamos construir um sistema de sensor de temperatura que demonstra o encapsulamento, mantendo dados sensíveis protegidos dentro de um módulo.
Você criará dois arquivos para organizar seu código:
sensor.rs: Defina uma structTemperatureSensorcom dois campos:location(String) ereading(f64). A struct deve ser pública para que possa ser usada em outros arquivos, mas mantenha ambos os campos privados — o código externo não deve ser capaz de acessar ou modificar diretamente os dados do sensor. Adicione um construtor públiconewque receba um nome de localização e uma leitura de temperatura inicial.main.rs: Importe seu módulo de sensor e crie umTemperatureSensorusando o construtor. Como os campos são privados, você não poderá imprimi-los diretamente — em vez disso, imprima uma mensagem de confirmação mostrando que o sensor foi criado com sucesso.
Este desafio foca no conceito central de campos privados: a struct é acessível, mas seus dados internos estão protegidos. O código externo só pode interagir com o sensor através dos métodos que você fornece (neste caso, apenas o construtor).
Sua saída deve seguir este formato exato:
Sensor created for: {location}Para acessar a localização para impressão, você precisará fazer com que sua função new imprima esta mensagem antes de retornar o sensor, já que o campo em si é privado.
Por exemplo, se você criar um sensor com a localização "Kitchen" e leitura 22.5, a saída seria:
Sensor created for: KitchenVocê receberá duas entradas: o nome da localização e a leitura inicial da temperatura.
Folha de consulta
Em Rust, você pode tornar uma struct pública enquanto mantém seus campos privados para alcançar o encapsulamento. Isso impede que o código externo acesse ou modifique diretamente os dados internos.
Para tornar um campo privado, basta omitir a palavra-chave pub:
pub struct Wallet {
balance: f64, // Sem pub = campo privado
}
impl Wallet {
pub fn new(initial: f64) -> Wallet {
Wallet { balance: initial }
}
}
Neste exemplo, Wallet é pública (pode ser usada fora do módulo), mas balance é privado (não pode ser acessado diretamente de fora).
O código externo pode criar instâncias usando construtores públicos, mas não pode ler ou modificar campos privados:
mod wallet;
use wallet::Wallet;
fn main() {
let w = Wallet::new(100.0);
// println!("{}", w.balance); // Erro! o campo é privado
// w.balance = -50.0; // Erro! não é possível acessar o campo privado
}
Esse encapsulamento garante que a struct controle seus próprios dados, e o código externo deve usar os métodos que você fornece para interagir com ela.
Experimente você mesmo
mod sensor;
use sensor::TemperatureSensor;
fn main() {
// Ler 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: Criar um TemperatureSensor usando o construtor
// A função new lidará com a impressão da mensagem de confirmação
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Object Oriented Programming
1Métodos e Comportamento
Introdução a Blocos de ImplementaçãoO Parâmetro SelfMétodos MutáveisFunções AssociadasMúltiplos Blocos de ImplementaçãoEncadeamento de MétodosRecapitulação - Ações de Retângulo4Projeto: Pet Virtual
Definindo o PetAlimentando o Pet7Traits Padrão
A Trait DebugA Trait DisplayClone e CopyTraits de IgualdadeRecapitulação - Ponto Imprimível10Projeto: Sistema de Documentos
A Trait DrawComponente de Texto2Encapsulamento e Módulos
Fundamentos de MódulosA Palavra-chave PublicCampos PrivadosGettersSettersRecapitulação - Cofre Seguro5Genéricos
Structs GenéricasMétodos GenéricosMúltiplos Tipos GenéricosFunções GenéricasRecapitulação - Ponto de Coordenada8Traits como Restrições
Sintaxe de Restrições de TraitRestrições MúltiplasA Cláusula WhereRetornando Tipos com TraitsRecapitulação - Impressora Genérica11Padrões de Projeto em Rust
Padrão NewtypeComposiçãoA Trait DropFrom e IntoRecapitulação - Mock de Smart Pointer3Enums Avançados
Enums com DadosMétodos em EnumsCorrespondência de Variantes de DadosO Enum Option RevisitadoRecapitulação - Enum Shape6Definição de Traits
O que é uma Trait?Implementando TraitsImplementações PadrãoSobrescrevendo PadrõesTraits com ParâmetrosRecapitulação - Media Player