Ruby-Programmierung: Algorithmen und Datenstrukturen
Aus Wikibooks
Zurück zu Ruby-Programmierung Hauptmenü
Inhaltsverzeichnis |
[Bearbeiten] Variablen und Konstanten
Vor noch gar nicht allzulanger Zeit wurde die IT noch EDV genannt, was für elektronische Datenverarbeitung steht. Diesem interessanten Ziel wollen wir uns nun etwas nähern. Um Daten verarbeiten zu können, müssen wir sie im Arbeitsspeicher speichern können. Dies geschieht mittels sogenannter Variablen. Diese haben einen eindeutigen Namen und zeigen auf eine Stelle im Arbeitsspeicher, wo die Daten gespeichert werden. Genau genommen zeigen wir als objektorientierte Programmierer wieder auf ein Objekt, welches unsere Daten enthält, aber damit wollen wir uns ja später beschäftigen. Schauen wir uns einfach mal ein Beispiel an:
vorname = "Carl"
nachname = "Meier"
alter = 42
name = vorname + " " + nachname
puts "Hallo " + name + " (" + alter.to_s + ")"
Um einen Wert im Arbeitsspeicher zu speichern, müssen wir ihn einer Variable zuweisen, dies geschieht mit dem Gleichheitszeichen. Immer wenn der Interpreter eine Zuweisung findet, wird er das Ergebnis der rechten Seite des Gleichheitszeichen berechnen und in der Variable auf der linken Seite speichern. Bei den ersten drei Zuweisungen muss nichts berechnet werden, da wir nur einen einfachen Wert zuweisen, aber man kann auch Werte berechnen lassen.
Der Name besteht in der Regel aus Vor- und Nachname, daher überlassen wir es doch einfach dem Interpreter, den Namen aus diesen Bestandteilen zusammen zu setzen. Dazu schreiben wir einfach die Variablen, die den Wert enthalten hin und sagen mit einem +, dass die Werte verbunden werden sollen. Dann würde name aber den Wert "CarlMeier" enthalten, daher setzen wir noch einen String in die Mitte, der nur ein Leerzeichen enthält. Wir sehen also, wir können Variablen genauso verwenden wie die Werte, die sie enthalten.
Variablen heißen so, weil ihr Inhalt variabel, also änderbar sein soll. Wir können z. B. mit einer Zuweisung einer Variable einen neuen Wert geben, der vorherige verfällt dabei. Manchmal ist es aber gar nicht erwünscht, dass der Wert veränderbar ist, daher gibt es sogenannte Konstanten, die genau wie Variablen funktioneren, aber ihren Wert nach der ersten Zuweisung bis zum Ende des Scripts nicht mehr ändern.
Namen von Konstanten beginnen immer mit einem Großbuchstaben, Variablen immer mit einem kleinen. Üblicherweise schreibt man bei Konstanten auch den Rest des Namens groß, aber das ist nicht unbedingt erforderlich.
PI = 3.14159 ProgName = "Hallo Welt"
[Bearbeiten] Schlüsselwörter
Schlüsselwörter sollten nicht als Variablennamen benutzt werden, da sonst der Interpreter/Compiler eine Fehlermeldung ausgibt.
alias and BEGIN begin break case class def defined? do else elsif END end ensure false for if in loop module next nil not or redo rescue retry return self super then true undef unless until when where while yield __FILE__ __LINE__
[Bearbeiten] Objekte
Wie in jeder objektorientierten Sprache wird in Ruby folgendes Prinzip realisiert:
- Im Programm verwendbar sind Objekte. Sie besitzen die Eigenschaften, Daten zu speichern und Botschaften zu verstehen.
- Jedes Objekt ist Instanz einer Klasse. Eine Klasse schreibt vor, was für Eigenschaften Objekte dieser Klasse speichern, welche Botschaften sie verstehen und wie sie auf diese Botschaften reagieren. Die Eigenschaften werden häufig als Instanzvariablen bezeichnet, Botschaften werden häufig Methoden genannt.
In Ruby herrscht folgende Besonderheit: Alles, worauf zugegriffen werden kann, ist ein Objekt; im Gegensatz zu anderen Programmiersprachen auch Zahlen oder Zeichen. Daraus folgt, dass selbst die einfachsten Elemente in Ruby Methoden besitzen; sie werden in ihren Klassen definiert.
[Bearbeiten] Methoden
Methoden werden mit dem Schlüsselwort def eingeleitet. Nach einer Parameterliste folgt der Methodenrumpf, welcher mit end abgeschlossen wird.
Beispiel:
def aneinanderhaengen(a, b) a.to_s + b.to_s end
Zu beachten ist hier, dass im Gegensatz zu vielen anderen Programmiersprachen das Schlüsselwort return weggelassen werden kann. Der Rückgabewert entspricht dem Rückgabewert der zuletzt ausgeführten Anweisung. Hier: das Aneinanderhängen der String-Repräsentationen der Parameter a und b.
[Bearbeiten] Blöcke
Methodenaufrufe können zusätzlich zu Parametern noch sogenannte Blöcke entgegennehmen. Ein sehr einfaches Beispiel hierfür ist Integer#times, wobei eine Zahl den Block entsprechend ihrem Wert x-mal aufruft:
3.times { puts "Hallo" }
Ausgabe:
Hallo Hallo Hallo
Optional können Blöcke Parameter aufnehmen. Diese werden zwischen zwei Pipe-Zeichen geschrieben:
3.times { |i| puts "Hallo Nummer " + i.to_s }
Hallo Nummer 0
Hallo Nummer 1
Hallo Nummer 2
Bei mehreren Parametern werden diese durch Kommata abgetrennt:
ENV.each { |k,v| puts k + ' = ' + v }
_ = /usr/local/bin/irb
PATH = /bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/usr/X11R6/bin:/usr/X11R6/sbin
DISPLAY = :0.0
SHELL = /usr/local/bin/zsh
WINDOWID = 46137348
COLORFGBG = default;default
COLORTERM = rxvt-xpm
TERM = rxvt
LC_CTYPE = en_GB.UTF-8
LANG = en_GB.UTF-8
LC_MESSAGES = en_GB.UTF-8
LC_TIME = en_GB.UTF-8
Blöcke können auch in eigenen Methoden verwendet und mit dem Schlüsselwort yield aufgerufen werden:
def tu yield end
tu { puts ’Hallo’ }
Hallo
Ruft man diese Methode nun ohne Block auf, so wird ein LocalJumpError geworfen:
tu LocalJumpError: no block given from (irb):2:in ‘tu’ from (irb):4 from :0
Auf soetwas kann man in der Methode mit block_given? prüfen:
def tu yield if block_given? end
Man kann den Block jedoch auch explizit in der Parameterliste mit einem Vorangestellten & angeben, womit man ihn auch für später beispielsweise in einer globalen Variable (vorangestelltes Dollarzeichen ($)) speichern kann:
def merke_block(&block)
$gemerkter_block = block
end
merke_block { puts "Gemerkter Block!" }
$gemerkter_block.call
Gemerkter Block!
Wie mit $gemerkter_block.class herausgefunden werden kann, ist die Variable ein Proc-Objekt. Um eine solche zu erstellen, benötigt man gar keine Extramethode, es genügt Proc.new oder lambda. Primitiv sieht diese Funktion so aus:
def lambda(&block) block end
Dies kann sehr einfach verwendet werden:
b = Proc.new { puts "Hallo" }
b.call
Hallo
[Bearbeiten] Klassen
Klassen sind in erster Linie wie in jeder objektorientierten Sprache Container für Daten mit Methoden. Variablen mit Gültigkeit für die Lebensdauer der Klasseninstanz (des Objekts) werden mit voranstehendem @ geschrieben und heissen Instanzvariablen.
Der Konstruktor ist eine ganz normale Instanzmethode und hört auf den Namen initialize:
class Drink
def initialize(name)
@name = name
end
def drink
puts "Drinking #{@name}"
end
end
Nun kann von der Klasse Drink ein Objekt erzeugt werden:
d = Drink.new('Juice')
Die Instanzvariable @name ist nun ein String "Juice". Auf das Objekt d, die Instanz, kann nun die Methode drink aufgerufen werden:
d.drink
Das erzeugt folgende Ausgabe:
Drinking Juice
[Bearbeiten] Vererbung
In einer objektorientierten Sprache ist natürlich auch Vererbung vorhanden:
class Mate < Drink
def initialize
super ’Club Mate’
end
end
Die Klasse Mate erbt die Eigenschaften und Methoden der Klasse Drink. Dafür hat sie einen parameterlosen Konstruktor, welcher mit dem Schlüsselwort super dieselbe Methode in der Elternklasse (den Konstruktor von Drink) mit einem Parameter aufruft.
Wir können nun ebenfalls eine Instanz von Mate erstellen:
m = Mate.new m.drink
Dies erzeugt folgende Ausgabe:
Drinking Club Mate

