Rust: ¿Funcional o POO? Elegimos el estilo para un código ideal

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción: Dos mundos en un mismo lenguaje

\n\n

Cuando empiezas a aprender Rust, rápidamente notas su posición única. Este lenguaje no te impone una única forma de pensar. A diferencia de Java (donde todo es un objeto) o Haskell (donde todo es una función), Rust te ofrece libertad de elección. Pero con esa libertad viene la responsabilidad: ¿qué enfoque elegir: el funcional o el orientado a objetos?

\n\n

Muchos desarrolladores que llegan a Rust desde el mundo de Python o C++ se sienten atraídos intuitivamente por la POO (programación orientada a objetos). Buscan clases, herencia y patrones familiares. Otros, inspirados por el mundo de Haskell o Scala, intentan escribir en Rust exclusivamente en estilo funcional, usando mónadas, inmutabilidad y composición.

\n\n

La verdad, como siempre, está en el medio. Rust es un lenguaje multiparadigma que te permite tomar lo mejor de ambos mundos. En este artículo, analizaremos cómo usar eficazmente el enfoque funcional en Rust y cuándo aplicar patrones orientados a objetos. Aprenderás a escribir código que no solo funcione, sino que también deleite por su elegancia.

\n\n

Fundamentos de POO en Rust: Traits en lugar de clases

\n\n

Aclaremos las cosas de inmediato. En Rust no hay clases en el sentido clásico. Pero eso no significa que no puedas usar POO. En lugar de clases, aquí se utilizan traits y structs. Son ellos los que permiten implementar encapsulamiento, polimorfismo e incluso cierto parecido a la herencia.

\n\n

Structs y métodos

\n\n

Las structs son tus «objetos». Defines los datos y luego, con impl, les agregas métodos:

\n\n
struct Player {\n    name: String,\n    health: i32,\n    level: u32,\n}\n\nimpl Player {\n    // Método constructor\n    fn new(name: &str) -> Self {\n        Player {\n            name: name.to_string(),\n            health: 100,\n            level: 1,\n        }\n    }\n\n    // Método que cambia el estado\n    fn take_damage(&mut self, damage: i32) {\n        self.health = (self.health - damage).max(0);\n    }\n\n    // Getter (método de acceso)\n    fn is_alive(&self) -> bool {\n        self.health > 0\n    }\n}\n
\n\n

Esto es puro estilo POO: tenemos estado (campos de la struct) y comportamiento (métodos). Rust proporciona encapsulamiento mediante el control de visibilidad (modificador pub).

\n\n

Polimorfismo a través de traits

\n\n

En lugar de la herencia de clases, en Rust se usa el polimorfismo a través de traits. Esto es más potente y seguro que la herencia clásica, ya que no te encuentras con el «problema del diamante» ni con la herencia accidental de comportamientos no deseados.

\n\n
trait Attackable {\n    fn attack(&self, target: &mut Player);\n}\n\nstruct Swordsman {\n    damage: i32,\n}\n\nimpl Attackable for Swordsman {\n    fn attack(&self, target: &mut Player) {\n        target.take_damage(self.damage);\n        println!("¡El espadachín infligió {} de daño!", self.damage);\n    }\n}\n\nstruct Mage {\n    spell_power: i32,\n    mana_cost: i32,\n}\n\nimpl Attackable for Mage {\n    fn attack(&self, target: &mut Player) {\n        target.take_damage(self.spell_power * 2);\n        println!("¡El mago lanzó una bola de fuego de potencia {}!", self.spell_power * 2);\n    }\n}\n
\n\n

Ahora puedes trabajar con cualquier objeto que implemente el trait Attackable, sin preocuparte por su tipo concreto:

\n\n
fn perform_attack(attacker: &impl Attackable, target: &mut Player) {\n    attacker.attack(target);\n}\n
\n\n

Esto se llama «tipado pato con esteroides» o polimorfismo estático. Rust verifica todo en tiempo de compilación, por lo que no obtendrás un error en tiempo de ejecución.

\n\n

Enfoque funcional: Iteradores y clausuras

\n\n

Ahora cambiemos

Blogs

Book Recommendations