Rust carece de soporte nativo para programación orientada a objetos, pero de todos modos puede usar estas técnicas para aprovechar el paradigma.

La programación orientada a objetos (POO) simplifica el diseño de software al enfatizar el uso de objetos para representar entidades y conceptos del mundo real. OOP fomenta la mantenibilidad al encapsular la funcionalidad dentro de los objetos.

Rust es un lenguaje flexible que admite programación funcional y de procedimientos. Aunque no admite la programación orientada a objetos de forma nativa, puede implementar conceptos de programación orientada a objetos utilizando los tipos de datos integrados de Rust.

Encapsulación en Rust

La encapsulación implica organizar el código en unidades autónomas que ocultan los detalles internos mientras exponer una interfaz pública para la interacción externa para minimizar la complejidad y mejorar el código mantenibilidad

Puede encapsular código Rust con módulos. Un módulo es una colección de elementos que incluyen funciones, estructuras, enumeraciones y constantes. Los módulos de Rust brindan funcionalidad para agrupar y definir límites entre partes de un programa.

instagram viewer

Uso de módulos para encapsular datos y funciones

Puede definir un módulo usando el modificación palabra clave seguida de un nombre:

modificación mi_módulo {
// los elementos del módulo van aquí
}

Puede organizar módulos jerárquicamente anidando sus declaraciones:

modificación módulo_padre {
modificación mi_módulo {
// los elementos del módulo van aquí
}
}

A continuación, puede hacer referencia a los módulos anidados con la jerarquía completa, separando cada módulo con dos puntos dobles, por ejemplo, módulo_padre:: mi_módulo.

De forma predeterminada, los elementos dentro de los módulos son privados y solo se puede acceder al código dentro del mismo módulo. Pero puede hacer que los módulos sean públicos usando el pub palabra clave:

modificación mi_módulo {
pubfnmi_funcion() {
// el cuerpo de la función va aquí
}
}

A continuación, puede acceder mi_funcion de otras partes de su programa.

Uso de rasgos para definir comportamientos

Otra forma en que Rust permite la encapsulación es mediante el uso de rasgos. Los rasgos definen comportamientos que los tipos pueden implementar y aseguran que diferentes tipos se ajusten a la misma interfaz.

pubrasgoImprimible {
fnimprimir(&ser);
}

pubestructuraMi tipo {
// campos de estructura aquí
}

impl Imprimible para Mi tipo {
fnimprimir(&ser) {
// implementacion aqui
}
}

El Imprimible rasgo tiene un imprimir método, y el Mi tipo struct implementa el Imprimible rasgo implementando el imprimir método.

Usando rasgos, puede asegurarse de que cualquier tipo que implemente el Imprimible rasgo tiene un imprimir método. Esto es útil cuando se trabaja con código genérico que necesita interoperar con diferentes tipos que comparten un comportamiento común.

Herencia en Rust

La herencia le permite definir una clase basada en otra diferente. La subclase heredará las propiedades y métodos de su padre.

En Rust, se le anima a utilizar la composición en lugar de la herencia. La composición es un proceso de creación de nuevos objetos mediante la combinación de los existentes. En lugar de crear una nueva clase que herede la funcionalidad de la clase base, puede crear una nueva estructura que contenga una instancia de la estructura base y sus campos.

Creación de nuevos tipos mediante la combinación de tipos existentes

Usará enumeraciones y estructuras para crear nuevos tipos. Las enumeraciones son útiles para tipos con valores finitos, y las estructuras pueden contener varios campos.

Puede crear un tipo de enumeración para diferentes tipos de animales.

enumeraciónAnimal {
Gato,
Perro,
Pájaro,
// ...
}

Alternativamente, puede crear una estructura que contenga campos para cada tipo de animal. Las estructuras pueden contener enumeraciones y otros tipos.

estructuraAnimal {
nombre: Cadena,
edad: u8,
tipo_animal: tipoanimal,
}

enumeraciónTipo de animal {
Gato,
Perro,
Pájaro,
// ...
}

El Animal struct contiene valores de la Tipo de animal tipo de enumeración.

Puede usar rasgos para implementar la herencia y agregar comportamiento a un tipo sin crear uno nuevo.

rasgoVolar {
fnvolar(&ser);
}

Así es como puede implementar el Volar rasgo para múltiples tipos.

estructuraPájaro {
nombre: Cadena,
envergadura: f32,
}

impl Volar para Pájaro {
fnvolar(&ser) {
imprimir!("{} ¡está volando!", ser.nombre);
}
}

estructuraAvión {
modelo: Cadena,
máxima velocidad: u32,
}

impl Volar para Avión {
fnvolar(&ser) {
imprimir!("{} ¡está volando!", ser.modelo);
}
}

El Pájaro y Avión Las estructuras implementan el Volar cadenas de caracteres e impresión con el Imprimir! macro.

Puedes llamar al volar en ambas estructuras sin conocer sus tipos específicos.

fnprincipal() {
dejar pájaro = pájaro {
nombre: Cadena::de("Águila"),
envergadura: 2.0,
};

dejar avión = avión {
modelo: Cadena::de("Boeing 747"),
máxima velocidad: 900,
};

dejar objetos_voladores: Vecdinámico Volar> = vec![&pájaro, &avión];

para objeto en objetos_voladores {
objeto.volar();
}
}

El principal función instancia la Avión y Pájaro tipos El objetos_voladores vector es un vector de las instancias del objeto, y el para el bucle atraviesa el vector y llama al volar método en las instancias.

Implementando polimorfismo en Rust

Una clase o tipo es polimórfico si varios tipos representan una interfaz. Dado que los rasgos proporcionan la funcionalidad para definir comportamientos en Rust, al mismo tiempo que proporcionan una interfaz común para escribir código genérico, puede usar los rasgos para implementar el polimorfismo.

Aquí hay un rasgo llamado Dibujable que define el comportamiento para renderizar objetos en la pantalla:

rasgoDibujable {
fndibujar(&ser);
}

Los tipos que implementan el rasgo Drawable pueden acceder al dibujar función.

estructuraRectángulo {
ancho: u32,
altura: u32,
}

impl Dibujable para Rectángulo {
fndibujar(&ser) {
// Representar el rectángulo en la pantalla
}
}

Puede escribir código genérico que dibuje objetos que implementen el Dibujable rasgo.

fndibujar_objeto(objeto: &T) {
objeto.dibujar();
}

El dibujar_objeto función toma un tipo genérico T como entrada que implementa el Dibujable rasgo y llama al dibujar método en el rasgo. Diferentes objetos pueden implementar el Dibujable rasgo y acceder a la funcionalidad.

Implementando Abstracción en Rust

La abstracción es el concepto OOP donde las clases y las interfaces son accesibles para objetos y tipos específicos. Puede implementar la abstracción en Rust con rasgos.

Aquí hay un rasgo de ejemplo para un reproductor multimedia:

rasgoMedios de comunicación {
fnjugar(&ser);
}

Estructuras y enumeraciones que implementan el Medios de comunicación El rasgo debe proporcionar una implementación para el jugar método.

estructuraCanción {
título: Cadena,
artista: Cadena,
}

impl Medios de comunicación para Canción {
fnjugar(&ser) {
imprimir!("Reproduciendo la canción: {} de {}", ser.título, ser.artista);
}
}

El Canción struct implementa el Medios de comunicación rasgo al proporcionar una implementación para el jugar método que imprime un mensaje con los campos del Canción estructuras a la consola.

fnprincipal() {
// Crea una instancia de la estructura Song
dejar canción = canción {
título: Cadena::de("Bohemian Rhapsody"),
artista: Cadena::de("Reina"),
};

// Llamar al método de reproducción en la instancia de la canción
cancion.reproducir();
}

El canción variable es una instancia de la Canción struct, y la variable puede acceder y llamar al jugar método.

Organizar Rust Code es fácil

La programación orientada a objetos ayuda con la organización del código. Gracias al sistema de módulos de Rust, puede organizar fácilmente su código Rust mientras implementa los conceptos OOP para su aplicación para mantener su código organizado, manejable e intuitivo.