Ruby-Programmierung: Kontrollstrukturen

Zurück zum Inhaltsverzeichnis.

Diese Seite beschäftigt sich mit Kontrollstrukturen. Um etwas auf die Frage einzugehen, was eine Programmiersprache ausmacht und warum andere Sprachen keine Programmiersprachen sind. Die wichtigsten beiden Eigenschaften einer Programmiersprache sind, Quellcode wiederholt und optional ausführen zu können. Für verschiedene Sprachen existieren unterschiedliche Implementierungen dieser beiden Grundlagen. Ruby kennt Verzweigungen, zur optionalen Ausführung von Programmtext. Es lassen sich innerhalb des Programmflusses Entscheidungen treffen und auf sie reagieren. Zum Beispiel, wenn eine falsche Benutzereingabe behandelt werden muss.

Für die wiederholte Ausführung von Programmteilen gibt es in Ruby drei wesentliche Möglichkeiten, mit aufsteigender Präferenz: Schleifen, Rekursionen und Iterationen. An dieser Stelle wird nur auf Schleifen eingegangen. Rekursionen sind Teil des Kapitels Methoden, während Iterationen im zweiten Teil des Buches thematisiert werden.

Verzweigungen

Bearbeiten

Für die Behandlung von Verzweigungen ist es zunächst nötig sich mit Vergleichs- und Logikoperatoren zu beschäftigen. Es geht darum Daten auf etwas hin zu prüfen, zum Beispiel, ob eine Zahl größer ist als ein erwarteter Wert und die Ergebnisse verschiedener Prüfungen logisch zu kombinieren. Die folgende Tabelle gibt eine Übersicht über die vorhandenen Vergleichs- und Logikoperatoren, wobei die einzelne Funktionalität in Abhängigkeit von den übergebenen Typen variieren kann.

Operator Erklärung
== Prüft auf Gleichheit
< Kleiner als
> Größer als
<= Kleiner gleich
>= Größer gleich
! logisches nicht
&& logisches und
|| logisches oder

Die eigentliche Verzweigung im Programmtext erfolgt über die Schlüsselwörter if, elsif, else und unless, denen ein Wahrheitswert übergeben wird, der typischerweise durch oben betrachtete Operatoren ermittelt wird. Das folgende Skript gibt dabei Beispiele für verschiedene Anwendungsfälle. Es gilt zu beachten, dass elsif ohne 'e' geschrieben wird.

a = 2
b = 3
if a > b
  puts "a ist groesser"
elsif b == 10
  puts "b ist zehn!"
else
  puts "Standard"
end

Jede Kontrollanweisung leitet dabei einen Block ein, in dem sie gilt. Beendet wird ein Block mit dem Schlüsselwort end. Beim Ausführen des Skripts wird der Text "Standard" ausgegeben, da weder a größer als b, noch b gleich zehn ist. Die Anweisung unless STATEMENT ist äuqivalent zur Anweisung if !STATEMENT, der Programmblock wird also nur Ausgeführt, wenn die Bedingung nicht erfüllt wird. In Ruby sind nur die Werte nil und false logisch falsch. Insbesondere Programmierer, die bereits C oder eine ähnliche Sprache können, müssen an dieser Stelle aufpassen, dass eine 0 logisch wahr ist.

Eine Möglichkeit seinen Programmtext stilistisch zu verbessern ist es, eine Kontrollabfrage hinter den eigentlichen Kontrollblock zu schreiben. Dieser Kontrollblock besteht dann lediglich aus einer Zeile, nämlich allem, was vor dem entsprechenden Schlüsselwort steht. Das Skript von oben lässt sich also auch in kürzerer Form schreiben. Dabei gilt zu beachten, dass inbesondere die fünfte Zeile deutlich weniger lesbar ist, als die entsprechende Zeile im obigen Skript.

a = 2
b = 3
puts "a ist groesser" if a > b
puts "b ist zehn!" if b == 10
puts "Standard" unless a > b || b == 10

Eine weitere Möglichkeit ist das Wählen der Verzweigung mit case ... when. Mit case wählt man aus, was man überprüfen möchte und mit when wechselt man die Fälle. Wie bei if-Anweisungen ist es Möglich mit else einen Default-Fall zu erzeugen, falls sonst nichts zutrifft. Die gleiche Behandlung mehrerer Fälle erfolgt durch Trennung mit einem Komma. Zum Beispiel:

a = 2

case a
when 1
  puts "Eins!"
when 2, 3
  puts "Zwei oder Drei!"
else
  puts "Irgendetwas!"
end

Schleifen

Bearbeiten

Die einfachste Form einer Schleife ist die Endlosschleife. Sie entsteht oftmals als Folge von Programmierfehlern, kann aber unter Umständen auch gewünscht sein, wenn sie zum Beispiel in Folge einer Benutzereingabe abgebrochen wird. Somit handelt es sich nicht um eine echte Endlosschleife.

loop do
  input = gets
  break if input == "exit\n"
  puts "Ihre Eingabe lautete: " + input
  next
  puts "Diese Zeile wird nie ausgegeben"
end

Wenn Sie dieses Skript starten und ein paar Eingaben tätigen, werden Sie feststellen, dass Sie beliebig oft Eingaben tätigen können und diese ausgegeben werden. In dem Skript finden sich die Schlüsselwörter next und break. Mit break verlässt man die aktuelle Schleife, in diesem Fall ist also if eingabe == "exit\n" die Abbruchbedingung für die Pseudoendlosschleife. Es sei noch einmal betont, dass eine wirkliche Endlosschleife selten erwünscht ist, da man das Programm nur noch extern beenden kann. Während man mit break also hinter die Schleife springt, springt next an den Anfang der Schleife, es steht einfach für den nächsten Schleifendurchlauf. Alle Formen von Schleifen sind ineinander umformbar, doch ist es offensichtlich, dass ein stetiges Prüfen der Abbruchbedingung am Anfang einer Endlosschleife syntaktisch nicht schön ist, deswegen gibt es zwei weitere Schleifenschlüsselwörter. Im folgenden Skript ist eine while- bzw. until-Schleife implementiert, deren Funktion dem eben dargestellten Skript gleicht. Die Schlüsselwörter while und until verhalten sich zueinander wie if und unless.

input = ""
until input == "exit\n"
  input = gets
  puts input
end

Eine weitere Möglichkeit eine Schleife zu bilden ist for. Diese Schleife kommt dabei nicht zu derselben Bedeutung wie ihr Synonym in C oder Java, sondern wird weitaus weniger eingesetzt. Sie wird insbesondere durch die Iterator-Methoden verdrängt, die eine weitaus mächtigere Möglichkeit bieten, Arrays und andere Datenstrukturen zu behandeln. Trotzdem sei eine for-Schleife der Vollständigkeit halber hier erwähnt, denn sie kann notwendig werden, wenn man eigene Iteratoren definieren möchte.

for i in (0..10)
  puts i
end

Bei dem Konstrukt (0..10) handelt es sich um eine Range, also alle Zahlen zwischen 0 und 10. Ranges gibt es in einer inklusiven Variante mit zwei Punkten und einer exklusiven Variante mit drei Punkten.

Fakultät

Bearbeiten

Die Fakultät ist eine mathematische Funktion auf den natürlichen Zahlen. Das Implementieren der Fakultät ist eine Standardaufgabe beim Lernen einer Programmiersprache, da man dafür die auf dieser Seite gelernten Kontrollstrukturen verwenden kann und man somit vertraute Strukturen aus anderen Programmiersprachen schnell wiedererkennt, oder auf die Unterschiede stößt. Die Fakultät ist wie folgt definiert:  , außerdem gilt  .

# fakultaet.rb
# Ermittelt die Fakultät einer vom Benutzer eingegebenen Zahl.

eingabe = ""
until eingabe == "exit\n"
  eingabe = gets
  n = eingabe.to_i
  if n < 0
    puts "Fehlerhafte Eingabe!"
    next
  elsif n == 0
    ergebnis = 1
  else
    ergebnis = 1
    until n == 1
      ergebnis *= n
      n -= 1
    end
  end
  puts "Die berechnete Fakultät ist: " + ergebnis.to_s  unless eingabe == "exit\n"
end

Wieder sollte Ihnen vieles vertraut vorkommen. Zur Erklärung des Algorithmus gibt es lediglich zu sagen, dass ergebnis mit 1 initialisiert wird und solange mit dem herunterzählenden n multipliziert wird, bis dieses den Wert 1 hat und die Fakultät fertig berechnet ist.

  • Zeile 07: .to_i dient der Typumwandlung zu einer natürlichen Zahl.
  • Zeile 08: Abfangen einer fehlerhaften, negativen Eingabe.
  • Zeile 16: ergebnis *= n ist äquivalent zu ergebnis = ergebnis * n

Für das häufig vorkommende if und else gibt es eine Kurzschreibweise mit  ? : . Dieser kryptische Operator stammt aus der Programmiersprache C, wo er hinzugefügt wurde, um Parameter für Funktionen auszuwählen. Er ist mit Vorsicht anzuwenden, da er den Lesefluss des Programms deutlich einschränken kann, was der Philosophie eines leicht lesbaren Programmtextes in Ruby zuwider ist. Er kann jedoch insbesondere bei kurzen Verzweigungen vorteilhaft sein. Folgende beiden Programmabschnitte sind dabei äquivalent:

# 1. Variante mit if und else
if 1 == 2
  puts "Etwas ist seltsam."
else
  puts "Hier ist alles korrekt."
end

# 2. Variante mit ? :
1 == 2 ? puts("Eins ist gleich zwei!") : puts("Nein, alles ist richtig.")