Rust: Funktional oder OOP? Den Stil für idealen Code wählen

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Einleitung: Zwei Welten in einer Sprache

\n\n

Wenn Sie anfangen, Rust zu lernen, bemerken Sie schnell seine einzigartige Position. Diese Sprache zwingt Ihnen nicht eine einzige Denkweise auf. Im Gegensatz zu Java (wo alles ein Objekt ist) oder Haskell (wo alles eine Funktion ist), bietet Ihnen Rust die Freiheit der Wahl. Aber mit dieser Freiheit kommt auch Verantwortung: Welchen Ansatz soll man wählen – funktional oder objektorientiert?

\n\n

Viele Entwickler, die aus der Welt von Python oder C++ zu Rust kommen, fühlen sich intuitiv zu OOP (objektorientierter Programmierung) hingezogen. Sie suchen nach Klassen, Vererbung und vertrauten Mustern. Andere, inspiriert von der Welt von Haskell oder Scala, versuchen, in Rust ausschließlich im funktionalen Stil zu schreiben, unter Verwendung von Monaden, Unveränderlichkeit und Komposition.

\n\n

Die Wahrheit liegt, wie immer, in der Mitte. Rust ist eine multiparadigmatische Sprache, die es Ihnen ermöglicht, das Beste aus beiden Welten zu nehmen. In diesem Artikel werden wir untersuchen, wie man den funktionalen Ansatz in Rust effektiv nutzt und wann man objektorientierte Muster anwenden sollte. Sie werden lernen, wie man Code schreibt, der nicht nur funktioniert, sondern auch mit seiner Eleganz erfreut.

\n\n

Grundlagen von OOP in Rust: Traits statt Klassen

\n\n

Lassen Sie uns gleich Klartext reden. In Rust gibt es keine Klassen im klassischen Sinne. Aber das bedeutet nicht, dass Sie OOP nicht verwenden können. Anstelle von Klassen werden hier Traits und Structs verwendet. Sie ermöglichen es, Kapselung, Polymorphismus und sogar eine gewisse Ähnlichkeit mit Vererbung zu implementieren.

\n\n

Structs und Methoden

\n\n

Structs sind Ihre „Objekte“. Sie definieren die Daten und fügen ihnen dann mit impl Methoden hinzu:

\n\n
struct Player {\n    name: String,\n    health: i32,\n    level: u32,\n}\n\nimpl Player {\n    // Konstruktor-Methode\n    fn new(name: &str) -> Self {\n        Player {\n            name: name.to_string(),\n            health: 100,\n            level: 1,\n        }\n    }\n\n    // Methode, die den Zustand ändert\n    fn take_damage(&mut self, damage: i32) {\n        self.health = (self.health - damage).max(0);\n    }\n\n    // Getter (Zugriffsmethode)\n    fn is_alive(&self) -> bool {\n        self.health > 0\n    }\n}\n
\n\n

Dies ist der reinste OOP-Stil: Wir haben einen Zustand (Struct-Felder) und Verhalten (Methoden). Rust gewährleistet die Kapselung durch Sichtbarkeitskontrolle (Modifikator pub).

\n\n

Polymorphismus durch Traits

\n\n

Anstelle von Klassenvererbung wird in Rust Polymorphismus durch Traits verwendet. Dies ist leistungsfähiger und sicherer als klassische Vererbung, da Sie nicht auf das „Rautenproblem“ oder die versehentliche Vererbung unnötigen Verhaltens stoßen.

\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!("Der Schwertkämpfer hat {} Schaden zugefügt!", 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!("Der Magier hat einen Feuerball der Stärke {} entfesselt!", self.spell_power * 2);\n    }\n}\n
\n\n

Jetzt können Sie mit jedem Objekt arbeiten, das das Attackable-Trait implementiert, ohne sich um seinen konkreten Typ kümmern zu müssen:

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

Dies wird als „Ententypisierung auf Steroiden“ oder statischer Polymorphismus bezeichnet. Rust überprüft alles zur Kompilierzeit, sodass Sie zur Laufzeit keinen Fehler erhalten.

\n\n

Funktionaler Ansatz: Iteratoren und Closures

\n\n

Jetzt schalten wir um

Blogs

Buchempfehlungen