06. Flusskontrolle

Ahhhh, Flusskontrolle. Hier kommt alles zusammen. Obwohl dieses Kapitel kürzer und einfacher ist als das Kapitel über Methoden, wird es eine Welt voller Programmiermöglichkeiten eröffnen. Nach diesem Kapitel werden wir in der Lage sein, wirklich interaktive Programme zu schreiben; in der Vergangenheit haben wir Programme geschrieben, die je nach Eingabe unterschiedliche Dinge sagen, aber nach diesem Kapitel werden sie auch unterschiedliche Dinge tun. Aber bevor wir das tun können, müssen wir in der Lage sein, Objekte in unserem Programm zu vergleichen. Wir brauchen...

Vergleichsmethoden

Lassen Sie uns das schnell hinter uns bringen, damit wir zu den Verzweigungen kommen können, wo die coolen Sachen passieren. Um zu sehen, ob ein Objekt größer oder kleiner als ein anderes ist, verwenden wir die Methoden > und <, wie folgt:

puts 1 > 2
puts 1 < 2
false
true

Kein Problem. Ebenso können wir mit den Methoden >= und <= herausfinden, ob ein Objekt größer-gleich (oder kleiner-gleich) einem anderen ist.

puts 5 >= 5
puts 5 <= 4
true
false

Schließlich können wir herausfinden, ob zwei Objekte gleich sind oder nicht, indem wir == (was bedeutet "sind diese Objekte gleich?") und != (was bedeutet "sind diese Objekte verschieden?") verwenden. Es ist wichtig, = nicht mit == zu verwechseln. = dient dazu, einer Variablen zu sagen, dass sie auf ein Objekt zeigen soll (Zuweisung), und == dient dazu, die Frage zu stellen: "Sind diese beiden Objekte gleich?".

puts 1 == 1
puts 2 != 1
true
true

Und natürlich können wir auch Strings vergleichen. Wenn Strings verglichen werden, vergleichen sie ihre lexikografische Ordnung, was im Grunde ihre Wörterbuchordnung bedeutet. Hund kommt im Wörterbuch vor Katze, also:

puts 'Hund' < 'Katze'
true

Es gibt jedoch einen Haken: Computer denken normalerweise, dass Großbuchstaben vor Kleinbuchstaben kommen (so speichern sie sie zum Beispiel in Schriftarten: alle Großbuchstaben zuerst, dann die Kleinbuchstaben). Das bedeutet, dass der Computer denken wird, dass 'Zoo' vor 'Ameise' kommt. Wenn Sie also herausfinden wollen, welches Wort in einem echten Wörterbuch zuerst kommen würde, stellen Sie sicher, dass Sie downcase (oder upcase oder capitalize) auf beide Wörter anwenden, bevor Sie versuchen, sie zu vergleichen.

Eine letzte Anmerkung vor den Verzweigungen: Die Vergleichsmethoden geben uns nicht die Strings 'true' und 'false'; sie geben uns die speziellen Objekte true und false (natürlich gibt uns true.to_s 'true', weshalb puts 'true' gedruckt hat). true und false werden die ganze Zeit verwendet in...

Verzweigungen (Branching)

"Verzweigung" ist ein einfaches, aber mächtiges Konzept. Tatsächlich ist es so einfach, dass ich wette, ich muss es überhaupt nicht erklären; ich zeige es Ihnen einfach:

puts 'Hallo, wie heißt du?'
name = gets.chomp
puts 'Hallo, ' + name + '.'

if name == 'Chris'
  puts 'Was für ein schöner Name!'
end
Hallo, wie heißt du?
Chris
Hallo, Chris.
Was für ein schöner Name!

Aber wenn wir einen anderen Namen eingeben...

Hallo, wie heißt du?
Chewbacca
Hallo, Chewbacca.

Und das ist Verzweigung. Wenn das, was nach dem if (wenn) kommt, true (wahr) ist, führen wir den Code zwischen dem if und dem end (ende) aus. Wenn das, was nach dem if kommt, false (falsch) ist, tun wir das nicht. Schlicht und einfach.

Ich habe den Code zwischen dem if und dem end eingerückt, weil ich denke, dass es einfacher ist, den Überblick über die Verzweigung zu behalten. Fast alle Programmierer tun dies, unabhängig davon, in welcher Sprache sie programmieren. Es mag in diesem einfachen Fall nicht so hilfreich erscheinen, aber wenn die Dinge komplexer werden, macht es einen riesigen Unterschied.

Oft möchten wir, dass ein Programm eine Sache tut, wenn ein Ausdruck true ist, und eine andere, wenn er false ist. Dafür ist else (sonst) da:

puts 'Ich bin ein Wahrsager.  Sag mir deinen Namen:'
name = gets.chomp

if name == 'Chris'
  puts 'Ich sehe große Dinge in deiner Zukunft.'
else
  puts 'Deine Zukunft ist... oh mein Gott!  Sieh dir die Zeit an!'
  puts 'Ich muss wirklich gehen, tut mir leid!'
end
Ich bin ein Wahrsager.  Sag mir deinen Namen:
Chris
Ich sehe große Dinge in deiner Zukunft.

Versuchen wir jetzt einen anderen Namen...

Ich bin ein Wahrsager.  Sag mir deinen Namen:
Ringo
Deine Zukunft ist... oh mein Gott!  Sieh dir die Zeit an!
Ich muss wirklich gehen, tut mir leid!

Verzweigung ist ein bisschen wie an eine Gabelung im Code zu kommen: Nehmen wir den Weg für Leute, deren Name == 'Chris' ist, oder nehmen wir else (sonst) den anderen Weg?

Und genau wie die Äste eines Baumes können Sie Zweige haben, die ihre eigenen Zweige enthalten:

puts 'Hallo und willkommen zum Deutschunterricht.'
puts 'Mein Name ist Frau Gabbard.  Und dein Name ist...?'
name = gets.chomp

if name == name.capitalize
  puts 'Bitte nimm Platz, ' + name + '.'
else
  puts name + '?  Du meinst ' + name.capitalize + ', richtig?'
  puts 'Weißt du nicht einmal, wie man deinen Namen buchstabiert??'
  antwort = gets.chomp

  if antwort.downcase == 'ja'
    puts 'Hmmph!  Nun, setz dich!'
  else
    puts 'RAUS!!'
  end
end
Hallo und willkommen zum Deutschunterricht.
Mein Name ist Frau Gabbard.  Und dein Name ist...?
chris
chris?  Du meinst Chris, richtig?
Weißt du nicht einmal, wie man deinen Namen buchstabiert??
ja
Hmmph!  Nun, setz dich!

Gut, ich werde es groß schreiben...

Hallo und willkommen zum Deutschunterricht.
Mein Name ist Frau Gabbard.  Und dein Name ist...?
Chris
Bitte nimm Platz, Chris.

Manchmal kann es verwirrend sein, herauszufinden, wo all die ifs, elses und ends hingehen. Was ich tue, ist, das end gleichzeitig mit dem if zu schreiben. Als ich also das obige Programm schrieb, sah es zuerst so aus:

puts 'Hallo und willkommen zum Deutschunterricht.'
puts 'Mein Name ist Frau Gabbard.  Und dein Name ist...?'
name = gets.chomp

if name == name.capitalize
else
end

Dann habe ich es mit Kommentaren gefüllt, Dinge im Code, die der Computer ignorieren wird:

puts 'Hallo und willkommen zum Deutschunterricht.'
puts 'Mein Name ist Frau Gabbard.  Und dein Name ist...?'
name = gets.chomp

if name == name.capitalize
  #  Sie ist höflich.
else
  #  Sie wird wütend.
end

Alles nach einem # gilt als Kommentar (außer natürlich, Sie befinden sich in einem String). Nachdem ich die Kommentare ausgefüllt hatte, ersetzte ich sie durch funktionierenden Code. Manche Leute lassen die Kommentare gerne drin; ich persönlich denke, gut geschriebener Code spricht für sich selbst. Ich habe früher mehr Kommentare geschrieben, aber da ich "fließender" in Ruby werde, schreibe ich sie immer weniger. Ich finde sie die meiste Zeit tatsächlich ablenkend. Es ist eine persönliche Entscheidung; Sie werden Ihren eigenen Stil finden (normalerweise wird sich Ihr Stil entwickeln). Mein nächster Schritt sah also so aus:

puts 'Hallo und willkommen zum Deutschunterricht.'
puts 'Mein Name ist Frau Gabbard.  Und dein Name ist...?'
name = gets.chomp

if name == name.capitalize
  puts 'Bitte nimm Platz, ' + name + '.'
else
  puts name + '?  Du meinst ' + name.capitalize + ', richtig?'
  puts 'Weißt du nicht einmal, wie man deinen Namen buchstabiert??'
  antwort = gets.chomp

  if antwort.downcase == 'ja'
  else
  end
end

Wieder habe ich das if, else und end alle zur gleichen Zeit geschrieben. Es hilft mir wirklich, den Überblick zu behalten, "wo ich bin" im Code. Es lässt die Arbeit auch einfacher erscheinen, weil ich mich auf einen kleinen Teil konzentrieren kann, wie das Ausfüllen des Codes zwischen dem if und dem else. Der andere Vorteil, es so zu machen, ist, dass der Computer das Programm in jedem Stadium verstehen kann. Jede der unfertigen Versionen des Programms, die ich Ihnen gezeigt habe, würde laufen. Sie waren nicht fertig, aber es waren funktionierende Programme. Auf diese Weise konnte ich es testen, während ich es schrieb, was mir half zu sehen, wie es vorankam und wo es noch Arbeit brauchte. Als es alle Tests bestand, wusste ich, dass ich fertig war!

Diese Tipps helfen Ihnen beim Schreiben von Programmen, die verzweigen, aber sie helfen auch bei der anderen Hauptart der Flusskontrolle:

Schleifen (Looping)

Oft werden Sie wollen, dass Ihr Computer dasselbe immer und immer wieder tut – schließlich sollen Computer darin gut sein.

Wenn Sie Ihrem Computer sagen, dass er etwas wiederholen soll, müssen Sie ihm auch sagen, wann er aufhören soll. Computer langweilen sich nie, also wenn Sie ihm nicht sagen, dass er aufhören soll, wird er es nicht tun. Wir stellen sicher, dass dies nicht passiert, indem wir dem Computer sagen, dass er bestimmte Teile eines Programms wiederholen soll, while (während) eine bestimmte Bedingung wahr ist. Dies funktioniert sehr ähnlich wie if:

befehl = ''

while befehl != 'tchau'
  puts befehl
  befehl = gets.chomp
end

puts 'Komm bald wieder!'
Hallo?
Hallo?
Hi!
Hi!
Sehr schon, dich kennenzulernen.
Sehr schon, dich kennenzulernen.
Oh... wie reizend!
Oh... wie reizend!
tchau
Komm bald wieder!

Und das ist eine Schleife. (Sie haben vielleicht die Leerzeile am Anfang der Ausgabe bemerkt; sie kommt vom ersten puts, vor dem ersten gets. Wie würden Sie das Programm ändern, um diese erste Zeile loszuwerden? Testen Sie es! Hat es genau wie das Programm oben funktioniert, abgesehen von dieser ersten Leerzeile?)

Schleifen ermöglichen es Ihnen, alle möglichen interessanten Dinge zu tun, wie ich mir sicher bin, dass Sie sich vorstellen können. Sie können jedoch auch Probleme verursachen, wenn Sie einen Fehler machen. Was ist, wenn Ihr Computer in einer Endlosschleife stecken bleibt? Wenn Sie glauben, dass dies passiert sein könnte, halten Sie einfach die Strg-Taste gedrückt und drücken Sie C.

Bevor wir jedoch anfangen, mit Schleifen herumzuspielen, lassen Sie uns ein paar Dinge lernen, um uns die Arbeit zu erleichtern.

Ein bisschen Logik

Schauen wir uns unser erstes Verzweigungsprogramm noch einmal an. Was wäre, wenn meine Frau nach Hause käme, das Programm sähe, es ausprobierte und es ihr nicht sagen würde, was für einen schönen Namen sie hat? Ich würde ihre Gefühle nicht verletzen wollen (oder auf der Couch schlafen), also schreiben wir es um:

puts 'Hallo, wie heißt du?'
name = gets.chomp
puts 'Hallo, ' + name + '.'

if name == 'Chris'
  puts 'Was für ein schöner Name!'
else
  if name == 'Katy'
    puts 'Was für ein schöner Name!'
  end
end
Hallo, wie heißt du?
Katy
Hallo, Katy.
Was für ein schöner Name!

Nun, es funktioniert... aber es ist kein sehr schönes Programm. Warum nicht? Die beste Regel, die ich je über Programmierung gelernt habe, war die DRY-Regel: Don't Repeat Yourself (Wiederhole dich nicht). Ich könnte ein kleines Buch darüber schreiben, warum das so eine gute Regel ist. In unserem Fall haben wir die Zeile Was für ein schöner Name! wiederholt. Warum ist das ein Problem? Nun, was wäre, wenn ich mich beim Umschreiben vertippt hätte? Was wäre, wenn ich schöner in beiden Zeilen in wunderschöner ändern wollte? Ich bin faul, erinnerst du dich? Im Grunde genommen, wenn ich möchte, dass mein Programm dasselbe tut, wenn es Chris oder Katy bekommt, dann sollte es wirklich dasselbe tun:

puts 'Hallo, wie heißt du?'
name = gets.chomp
puts 'Hallo, ' + name + '.'

if (name == 'Chris' or name == 'Katy')
  puts 'Was für ein schöner Name!'
end
Hallo, wie heißt du?
Katy
Hallo, Katy.
Was für ein schöner Name!

Viel besser. Damit es funktioniert, habe ich or (oder) verwendet. Die anderen logischen Operatoren sind and (und) und not (nicht). Es ist immer gut, Klammern zu verwenden, wenn man mit diesen arbeitet. Sehen wir uns an, wie sie funktionieren:

ichBinChris  = true
ichBinLila = false
ichMagEssen = true
ichEsseSteine = false

puts (ichBinChris and ichMagEssen)
puts (ichMagEssen and ichEsseSteine)
puts (ichBinLila and ichMagEssen)
puts (ichBinLila and ichEsseSteine)
puts
puts (ichBinChris or ichMagEssen)
puts (ichMagEssen or ichEsseSteine)
puts (ichBinLila or ichMagEssen)
puts (ichBinLila or ichEsseSteine)
puts
puts (not ichBinLila)
puts (not ichBinChris)
true
false
false
false

true
true
true
false

true
false

Der einzige, der Sie austricksen könnte, ist or. Im Deutschen verwenden wir oft "oder", um "das eine oder das andere, aber nicht beides" zu meinen. Zum Beispiel könnte Ihre Mutter sagen: "Zum Nachtisch kannst du Kuchen oder Torte haben." Sie meinte nicht, dass Sie beides haben könnten! Ein Computer hingegen verwendet or, um "das eine oder das andere oder beides" zu bedeuten. (Eine andere Art, es zu sagen, ist: "mindestens eines davon ist wahr".) Deshalb machen Computer mehr Spaß als Mütter.

Ein paar Dinge zum Ausprobieren

  • "99 Flaschen Bier an der Wand..." Schreiben Sie ein Programm, das den Text zu diesem beliebten Klassiker ausgibt, der bis zu 100 Flaschen geht.
  • Schreiben Sie ein Taube Oma-Programm. Was auch immer Sie zur Oma sagen (was auch immer Sie eingeben), sie sollte mit HÄ?! SPRICH LAUTER, JUNGE! antworten, es sei denn, Sie schreien es (geben Sie alles in Großbuchstaben ein). Wenn Sie schreien, kann sie Sie hören (oder zumindest denkt sie das) und schreit zurück: NEIN, NICHT SEIT 1938! Um Ihr Programm wirklich glaubwürdig zu machen, lassen Sie die Oma jedes Mal ein anderes Jahr schreien; vielleicht ein beliebiges Jahr zwischen 1930 und 1950. (Dieser Teil ist optional und wäre viel einfacher, wenn Sie den Abschnitt über Rubys Zufallszahlengenerator am Ende des Methodenkapitels lesen würden.) Sie können nicht aufhören, mit der Oma zu reden, bis Sie TCHAU schreien.
    • Tipp: Vergessen Sie chomp nicht! 'TCHAU' mit einem Enter ist nicht dasselbe wie 'TCHAU' ohne!
    • Tipp 2: Versuchen Sie darüber nachzudenken, welche Teile Ihres Programms immer wieder passieren sollten. Alle diese sollten in Ihrer while-Schleife sein.
  • Erweitern Sie Ihr Taube Oma-Programm: Was ist, wenn Oma nicht will, dass Sie gehen? Wenn Sie TCHAU schreien, könnte sie so tun, als würde sie Sie nicht hören. Ändern Sie Ihr vorheriges Programm so, dass Sie dreimal hintereinander TCHAU schreien müssen. Stellen Sie sicher, dass Sie Ihr Programm testen: Wenn Sie dreimal TCHAU schreien, aber nicht hintereinander, sollten Sie immer noch mit Oma reden.
  • Schaltjahre. Schreiben Sie ein Programm, das nach einem Startjahr und einem Endjahr fragt und dann alle Schaltjahre dazwischen (und einschließlich dieser, wenn sie auch Schaltjahre sind) mit puts ausgibt. Schaltjahre sind Jahre, die durch vier teilbar sind (wie 1984 und 2004). Jahre, die durch 100 teilbar sind, sind jedoch keine Schaltjahre (wie 1800 und 1900), es sei denn, sie sind durch 400 teilbar (wie 1600 und 2000, die tatsächlich Schaltjahre waren). (Ja, es ist alles ziemlich verwirrend, aber nicht so verwirrend wie Dezember mitten im Winter, was am Ende passieren würde).

Wenn Sie damit fertig sind, machen Sie eine Pause! Sie haben schon viel gelernt. Herzlichen Glückwunsch. Sind Sie überrascht von der Anzahl der Dinge, die Sie dem Computer befehlen können? Noch ein paar Kapitel und Sie werden fast alles programmieren können. Wirklich! Schauen Sie sich all die Dinge an, die Sie jetzt tun können, die Sie vor dem Erlernen von Schleifen und Verzweigungen nicht tun konnten.

Lassen Sie uns jetzt etwas über eine neue Art von Objekt lernen, eines, das Listen anderer Objekte verfolgt: Arrays.