Rust carece de suporte nativo para OOP, mas você pode usar essas técnicas para aproveitar o paradigma de qualquer maneira.

A Programação Orientada a Objetos (OOP) simplifica o design de software enfatizando o uso de objetos para representar entidades e conceitos do mundo real. A OOP incentiva a manutenção ao encapsular a funcionalidade dentro dos objetos.

Rust é uma linguagem flexível que suporta programação funcional e procedural. Embora não suporte a programação orientada a objetos nativamente, você pode implementar os conceitos OOP usando os tipos de dados integrados do Rust.

Encapsulamento em Rust

O encapsulamento envolve a organização do código em unidades independentes que ocultam detalhes internos enquanto expor uma interface pública para interação externa para minimizar a complexidade e melhorar o código manutenibilidade.

Você pode encapsular o código Rust com módulos. Um módulo é uma coleção de itens, incluindo funções, structs, enums e constantes. Os módulos Rust fornecem funcionalidade para agrupar e definir limites entre as partes de um programa.

instagram viewer

Usando módulos para encapsular dados e funções

Você pode definir um módulo usando o mod palavra-chave seguida de um nome:

mod meu_módulo {
// os itens do módulo vão aqui
}

Você pode organizar módulos hierarquicamente aninhando suas declarações:

mod parent_module {
mod meu_módulo {
// os itens do módulo vão aqui
}
}

Você pode então se referir a módulos aninhados com a hierarquia completa, separando cada módulo com dois pontos duplos, por exemplo, parent_module:: my_module.

Por padrão, os itens dentro dos módulos são privados e acessíveis apenas ao código dentro do mesmo módulo. Mas você pode tornar os módulos públicos usando o bar palavra-chave:

mod meu_módulo {
barfnminha_função() {
// o corpo da função vai aqui
}
}

Você pode então acessar minha_função de outras partes do seu programa.

Usando Traços para Definir Comportamentos

Outra maneira pela qual o Rust permite o encapsulamento é por meio do uso de traits. As características definem os comportamentos que os tipos podem implementar e garantem que diferentes tipos estejam em conformidade com a mesma interface.

barcaracterísticaImprimível {
fnimprimir(&auto);
}

barestruturaMeu tipo {
// struct campos aqui
}

implicar Imprimível para Meu tipo {
fnimprimir(&auto) {
// implementação aqui
}
}

O Imprimível traço tem um imprimir método, e o Meu tipo struct implementa o Imprimível característica implementando o imprimir método.

Usando traits, você pode garantir que qualquer tipo que implemente o Imprimível traço tem um imprimir método. Isso é útil ao trabalhar com código genérico que precisa interoperar com diferentes tipos que compartilham um comportamento comum.

Herança em Rust

A herança permite definir uma classe com base em outra diferente. A subclasse herdará as propriedades e métodos de seu pai.

No Rust, você é encorajado a usar composição em vez de herança. A composição é um processo de criação de novos objetos combinando os existentes. Em vez de criar uma nova classe que herda a funcionalidade da classe base, você pode criar uma nova estrutura que contém uma instância da estrutura base e seus campos.

Criando novos tipos combinando tipos existentes

Você usará enums e structs para criar novos tipos. Enums são úteis para tipos com valores finitos e structs podem conter vários campos.

Você pode criar um tipo de enumeração para diferentes tipos de animais.

enumerarAnimal {
Gato,
Cachorro,
Pássaro,
// ...
}

Como alternativa, você pode criar uma estrutura contendo campos para cada tipo de animal. As estruturas podem conter enums e outros tipos.

estruturaAnimal {
nome: Corda,
idade: u8,
animal_type: AnimalType,
}

enumerarAnimalType {
Gato,
Cachorro,
Pássaro,
// ...
}

O Animal struct contém valores do AnimalType tipo de enumeração.

Você pode usar características para implementar herança e adicionar comportamento a um tipo sem criar um novo.

característicaVoar {
fnvoar(&auto);
}

Veja como você pode implementar o Voar característica para vários tipos.

estruturaPássaro {
nome: Corda,
Envergadura: f32,
}

implicar Voar para Pássaro {
fnvoar(&auto) {
println!("{} está voando!", auto.nome);
}
}

estruturaAvião {
modelo: Corda,
velocidade máxima: u32,
}

implicar Voar para Avião {
fnvoar(&auto) {
println!("{} está voando!", auto.modelo);
}
}

O Pássaro e Avião structs implementam o Voar trace e imprima strings com o Imprimir! macro.

Você pode ligar para o voar método em ambas as estruturas sem conhecer seus tipos específicos.

fnprincipal() {
deixar pássaro = pássaro {
nome: Corda::de("Águia"),
Envergadura: 2.0,
};

deixar plano = Plano {
modelo: Corda::de("Boeing 747"),
velocidade máxima: 900,
};

deixar objetos_voadores: vecdin Voar> = você![&pássaro, &plano];

para objeto em objetos_voadores {
object.fly();
}
}

O principal função instancia o Avião e Pássaro tipos. O objetos_voadores vector é um vetor das instâncias do objeto, e o para loop percorre o vetor e chama o voar nas instâncias.

Implementando Polimorfismo em Rust

Uma classe ou tipo é polimórfico se vários tipos representam uma interface. Como as características fornecem a funcionalidade para definir comportamentos em Rust, enquanto fornecem uma interface comum para escrever código genérico, você pode usar Traits para implementar polimorfismo.

Aqui está uma característica chamada Desenhavel que define o comportamento para renderizar objetos na tela:

característicaDesenhavel {
fnempate(&auto);
}

Tipos que implementam o traço Drawable podem acessar o empate função.

estruturaRetângulo {
largura: u32,
altura: u32,
}

implicar Desenhavel para Retângulo {
fnempate(&auto) {
// Renderiza o retângulo na tela
}
}

Você pode escrever código genérico que desenha objetos que implementam o Desenhavel característica.

fndesenhar_objeto(objeto: &T) {
object.draw();
}

O desenhar_objeto função recebe um tipo genérico T como entrada que implementa o Desenhavel traço e chama o empate método no traço. Objetos diferentes podem implementar o Desenhavel trait e acessar a funcionalidade.

Implementando Abstração em Rust

Abstração é conceito OOP onde classes e interfaces são acessíveis a objetos e tipos especificados. Você pode implementar a abstração no Rust com traits.

Aqui está um exemplo de característica para um reprodutor de mídia:

característicameios de comunicação {
fnjogar(&auto);
}

Estruturas e enumerações que implementam o meios de comunicação trait deve fornecer uma implementação para o jogar método.

estruturaCanção {
título: Corda,
artista: Corda,
}

implicar meios de comunicação para Canção {
fnjogar(&auto) {
println!("Tocando música: {} de {}", auto.título, auto.artista);
}
}

O Canção struct implementa o meios de comunicação característica, fornecendo uma implementação para o jogar método que imprime uma mensagem com os campos do Canção estruturas para o console.

fnprincipal() {
// Cria uma instância da estrutura Song
deixar música = música {
título: Corda::de("Bohemian Rhapsody"),
artista: Corda::de("Rainha"),
};

// Chama o método play na instância da música
música.play();
}

O canção variável é uma instância do Canção struct, e a variável pode acessar e chamar o jogar método.

Organizar código Rust é fácil

A programação orientada a objetos ajuda na organização do código. Graças ao sistema de módulos do Rust, você pode organizar facilmente seu código Rust enquanto implementa os conceitos OOP para seu aplicativo para manter seu código organizado, gerenciável e intuitivo.