Eine Methode oder Funktion beschreibt im Grunde ein Bündel von Ausdrücken, also Codezeilen, die immer wieder ausgeführt werden können, ohne noch einmal getippt werden zu müssen. Sie werden mit dem Schlüsselwort def erstellt und können sehr komplex werden. Eine extrem einfach Methodendefinition sieht aber schon so aus:
1
2
3
4
5
|
def hallo
puts "Hallo!"
end
#Die Methode kann dann einfach über ihren Namen aufgerufen werden:
hallo #=> Hallo! |
Es gibt allerdings einige Beschränkungen in der Wahl von Methodennamen:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
#Keine Nicht-ASCII-Zeichen
def äöüß§
end
#Keine Operatoren im Namen (außer es ist NUR ein Operator)
def a+b
end
#Keine Schlüsselwörter
def if
end
#Keine Zahlen am Anfang
def 4t
end
#Keine Punkte (außer im Sinne von Klassenmethoden)
def a.b
end |
Argumente
Methoden sind nicht starr; sie können Argumente oder Parameter erhalten, die ihr Verhalten beeinflussen oder einfach nur ausgewertet werden. Um einer Methode Argumente zu übergeben, schreibt man sie einfach hinter die Methodendefinition, wahlweise mit Klammern oder ohne. Diese Argumente fungieren dann als zum Methodenblock lokale Variablen, können also von außen nicht abgerufen werden und werden vom GC entfernt, sobald die Methode zu Ende ist. Eine einfache Methode, die ihr Argument auswertet, könnte so aussehen:
1
2
3
4
|
def plus_eins(zahl)
puts zahl + 1
end
plus_eins(3) #=> 4 |
Die Klasse eines Arguments ist unwichtig; Ruby prüft Argumente nur, ob sie das können, was von ihnen verlangt wird. Dies wird im Artikel Duck Typing näher erläutert.
By reference/by value
Methodenargumente werden in Ruby by reference übergeben, außer es handelt sich um einen Immediate Value:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
def meine_methode(arg)
arg[0] = 10
end
ary = [0, 1]
meine_methode(ary)
p ary #=> [10, 1]
#Ein Fixnum ist ein Immediate Value:
def plus_gleich_eins(zahl)
zahl += 1
end
z = 3
plus_gleich_eins(zahl)
puts z #=> 3 |
Optionale Argumente
Manche Methoden erfordern es nicht zwingend, dass ein Argumente übergeben wird, sie enthalten optionale Argumente. Optionale Argumente müssen immer nach den verpflichtenden Argumenten definiert werden und werden nach der Syntax opt1 = def1 erstellt:
1
2
3
4
5
6
7
8
9
|
def mit_opts(pflicht1, opt1 = "Optionales Argument")
puts "#{pflicht1} und #{opt1} erhalten!"
end
mit_opts
#=> ArgumentError
mit_opts("Hallo!")
#=> Hallo! und Optionales Argument erhalten!
mit_opts("Hallo", "Bye!")
#=> Hallo! und Bye! erhalten! |
Benannte Argumente
Eigentlich erlaubt Ruby keine benannten Argumente, doch es gibt einen Trick, das zu umgehen: Man nimmt einfach ein Hash als Argument:
1
2
3
4
5
6
|
def bennant(opts = {:bennant1 = "Hallo", :benannt2 = "Welt!"})
puts opts[:benannt1].to_s + " " + opts[:benannt2].to_s
end
#Ruby hat syntaktischen Zucker parat, der die geschweiften Klammern in Methodenaufrufen unnötig macht
benannt(:benannt1 => "Wiedersehen", :benannt2 => "Welt!")
#=> Wiedersehen Welt! |
Variable Argumentzahl (Methodenüberladung)
Es ist in Ruby nicht möglich, Methoden zu überladen. Stattdessen kann man eine variable Argumentanzahl benutzen, die der Methode dann als Array übergeben wird. Die Variable, welche die variablen Argumente aufnehmen soll, folgt, wenn vorhanden, nach den optionalen Argumenten und mit einem * davor:
1
2
3
4
5
6
7
8
|
def variable_args(pflicht1, opt1 = "T", *args)
p args
end
variable_args("X", "U") #=> []
variable_args("X", "U", "TT", "Z") #=> ["TT", "Z"]
def nur_variable_args(*args)
#...
end |
yield und Blockargument
yield
Natürlich gibt es auch Iteratoren, die man selbst definieren kann. Man kann einfach das Schlüsselwort yield benutzen, und schon wird der einer Methode mitgegebene Codeblock ausgeführt. Um zu überprüfen, ob überhaupt ein Block da ist, kann man Kernel#block_given? verwenden.
1
2
3
4
5
6
7
8
9
10
11
12
|
def mit_block
if block_given?
yield
else
puts "No block given!"
end
end
mit_block #=> No block given!
mit_block do
puts "Block!"
end
#=> Block! |
Man kann yield Argumente übergeben, die dann vom Block »abgeholt« werden können:
1
2
3
4
5
6
7
8
|
def mit_block
if block_given?
yield("Block given!")
else
puts "No block given!"
end
end
mit_block{|arg| puts arg} #=> Block given! |
Blockargument
Wenn yield nicht genug ist, kann man auch ein Blockargument definieren, indem man einem Variablennamen ein & voranstellt. Das Blockargument muss immer das letzte Argument sein, nach verpflichtenden, optionalen und variablen Argumenten. Es enhält den mitgegebenen Codeblock als Proc-Objekt, dem in call wie bei yield auch Argumente mitgegeben werden können.
1
2
3
4
|
def mit_proc(&block)
puts block.call
end
mit_proc{"Hello World"} #=> Hello World |
Rückgabewerte
Eine Methode kann einen Wert zurückgeben, indem sie das Schlüsselwort return benutzt. Wenn eine Methode return erreicht, stoppt sie und gibt den angegebenen Wert zurück. Wenn man keinen Wert übergibt, wird das Ergebnis des letzten Ausdrucks verwendet.
1
2
3
4
5
|
def plus_eins(zahl)
return zahl + 1
puts "Das hier wird nie ausgeführt."
end
puts plus_eins(2) #=> 3 |
Optionales return
return ist optional, wie man ja auch an den oberen Beispielen gesehen hat. Wenn man return weglässt heißt das aber nicht, dass eine Methode keinen Wert bzw. nil zurückgibt, stattdessen wird einfach der letzte ausgewertete Ausdruck zurückgegeben:
1
2
3
4
|
def no_return
1 + 1
end
puts no_return #=> 2 |
Methodenarten
Instanzmethoden
Eine Instanzmethode ist eine Methode, die von Instanzen von Klassen aufgerufen werden kann:
1
2
3
4
5
6
7
|
class Klasse
def instanzmethode
puts "Hello world!"
end
end
x = Klasse.new
x.instanzmethode #=> Hello world! |
Klassenmethoden
Eine Klassenmethode wird von einer Klasse oder einem Modul ausgeführt.
1
2
3
4
5
6
7
8
9
10
11
12
|
module A
class B
def self.klassenmethode
puts "Klasse B"
end
end
def self.modulmethode
puts "Modul A"
end
end
A::B.klassenmethode #=> Klasse B
A.modulmethode #=> Modul A |
Singletonmethoden
Singletonmethoden sind Methoden, die nur ein spezielles Objekt beherrscht; Klassenmethoden zum Beispiel sind Singletonmethoden auf dem Objekt einer Klasse.
1
2
3
4
5
6
7
8
9
|
class A
end
x = A.new
y = A.new
def x.singletonmethode
puts "hello"
end
x.singletonmethode #=> hello
y.singletonmethode #=> NoMethodError |
Zusammenfassung der Syntax
Die Syntax einer Methode lautet also:
def [[objekt.]][methodenname]([verpflichtende_argumente][[, optionale_argumente]][[, *variable_argumente]][[, &blockargument]])
[Code]
[[yield]]
[[return [[rückgabewert]]]]
end
Aliasing
Methoden zusätzlich zu ihrem Namen einen weiteren Namen zu geben, kann man über Aliasing erreichen. Dadurch wird eine Kopie der Methode angefertigt, die exakt dasselbe macht wie ihr Original, nur eben unter anderem Namen. Man kann das auch als "BackUp-Technik" benutzen, da man auf diese Art und Weise die Originalmethode einfach überschreiben kann, die Kopie aber weiterhin das gleiche wie vorher macht. Die Syntax für das alias-Schlüsselwort ist wie folgt:
alias neuer_methodenname alter_methodenname
Zwischen beiden Namen ist kein Komma!
Instanzalias
Aliasing von Instanzmethoden ist einfach machbar:
1
2
3
4
5
|
def a
puts "a"
end
alias b a
b #=> a |
Klassenalias
Bei Klassenmethoden ist es schon ein wenig kniffliger.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
class A
def self.a
puts "a"
end
alias b a
end
#=> NoMethodError
#Einfach den syntaktischen Zucker herausnehmen: Klassenmethoden sind Instanzmethoden der Singletonklasse einer Klasse, also:
class A
class << self
def a #Die Methode könnte auch als self.a in der Klasse A definiert werden, aber das hier dient der Übersichtlichkeit
puts "a"
end
alias b a
end
end
A.b #=> a |
Modulalias
Ein Alias einer Modulmethode kann genauso erstellt werden wie der einer Klassenmethode.
1
2
3
4
5
6
7
8
9
|
module A
def A.a
puts "a"
end
class << self
alias b a
end
end
A.b #=> a |
Änderungen an Methoden und der Klasse Method zu Ruby 1.9
Hier werden Änderungen an Methoden zu Ruby 1.9.1 gelistet, sobald ein FeatureFreeze stattgefunden hat.
Siehe auch