Methoden
Methoden implementieren die Funktionalität Ihres Programms. Hier ist eine einfache Methodendefinition
def one_plus_one 1 + 1 end
Eine Methodendefinition besteht aus dem Schlüsselwort def, einem Methodennamen, dem Körper der Methode, dem return-Wert und dem Schlüsselwort end. Wenn die Methode aufgerufen wird, wird der Körper der Methode ausgeführt. Diese Methode gibt 2 zurück.
Seit Ruby 3.0 gibt es auch eine Kurzschreibweise für Methoden, die aus genau einem Ausdruck bestehen
def one_plus_one = 1 + 1
Dieser Abschnitt behandelt nur die Definition von Methoden. Siehe auch die Syntaxdokumentation zum Aufrufen von Methoden.
Methodennamen
Methodennamen können eine der Operatoren sein oder müssen mit einem Buchstaben oder einem Zeichen mit gesetztem achten Bit beginnen. Sie dürfen Buchstaben, Zahlen, einen _ (Unterstrich) oder ein Zeichen mit gesetztem achten Bit enthalten. Die Konvention ist, Unterstriche zur Trennung von Wörtern in einem Methodennamen mit mehreren Wörtern zu verwenden
def method_name puts "use underscores to separate words" end
Ruby-Programme müssen in einem US-ASCII-kompatiblen Zeichensatz wie UTF-8, ISO-8859-1 usw. geschrieben sein. In solchen Zeichensätzen zeigt ein gesetztes achtes Bit ein erweitertes Zeichen an. Ruby erlaubt Methodennamen und andere Bezeichner, solche Zeichen zu enthalten. Ruby-Programme dürfen einige Zeichen wie ASCII NUL (\x00) nicht enthalten.
Die folgenden sind Beispiele für gültige Ruby-Methoden
def hello "hello" end def こんにちは puts "means hello in Japanese" end
Typischerweise sind Methodennamen US-ASCII-kompatibel, da die Tasten zu ihrer Eingabe auf allen Tastaturen vorhanden sind.
Methodennamen dürfen mit einem ! (Bang oder Ausrufezeichen), einem ? (Fragezeichen) oder einem = (Gleichheitszeichen) enden.
Bang-Methoden (! am Ende des Methodennamens) werden wie jede andere Methode aufgerufen und ausgeführt. Nach Konvention gilt eine Methode mit einem Ausrufezeichen oder Bang jedoch als gefährlich. In der Kernbibliothek von Ruby bedeutet eine gefährliche Methode, dass eine Methode, die mit einem Bang (!) endet, anzeigt, dass sie im Gegensatz zu ihrem Nicht-Bang-Äquivalent ihren Empfänger dauerhaft modifiziert. Fast immer hat die Ruby-Kernbibliothek ein Nicht-Bang-Gegenstück (Methodenname, der NICHT mit ! endet) zu jeder Bang-Methode (Methodenname, der mit ! endet), die den Empfänger nicht modifiziert. Diese Konvention gilt typischerweise für die Ruby-Kernbibliothek, gilt aber möglicherweise nicht für andere Ruby-Bibliotheken.
Methoden, die mit einem Fragezeichen enden, geben nach Konvention Boole'sche Werte zurück, aber sie müssen nicht immer nur true oder false zurückgeben. Oft geben sie ein Objekt zurück, um einen wahren Wert (oder einen "wahrheitsfähigen" Wert) anzuzeigen.
Methoden, die mit einem Gleichheitszeichen enden, zeigen eine Zuweisungsmethode an.
class C def attr @attr end def attr=(val) @attr = val end end c = C.new c.attr #=> nil c.attr = 10 # calls "attr=(10)" c.attr #=> 10
Zuweisungsmethoden können nicht mit der Kurzschreibweise definiert werden.
Dies sind Methodennamen für die verschiedenen Ruby-Operatoren. Jeder dieser Operatoren akzeptiert nur ein Argument. Nach dem Operator folgt die typische Verwendung oder der Name des Operators. Die Schaffung einer alternativen Bedeutung für den Operator kann zu Verwirrung führen, da der Benutzer erwartet, dass Plus Dinge addiert, Minus Dinge subtrahiert usw. Außerdem können Sie die Priorität der Operatoren nicht ändern.
+-
add
--
subtrahieren
*-
multiplizieren
**-
Potenz
/-
dividieren
%-
Modulodivision,
String#% &-
UND
|-
ODER
^-
XOR (exklusives ODER)
>>-
Rechtsverschiebung
<<-
Linksverschiebung, anhängen
==-
gleich
!=-
ungleich
===-
Fallgleichheit. Siehe
Object#=== =~-
Musterabgleich. (Nicht nur für reguläre Ausdrücke)
!~-
stimmt nicht überein
<=>-
Vergleich aka Spaceship-Operator. Siehe
Comparable <-
kleiner als
<=-
kleiner als oder gleich
>-
größer als
>=-
größer als oder gleich
Um unäre Methoden Minus und Plus zu definieren, folgen Sie dem Operator mit einem @ wie in +@
class C def -@ puts "you inverted this object" end end obj = C.new -obj # prints "you inverted this object"
Das @ wird benötigt, um unäre Minus- und Plus-Operatoren von binären Minus- und Plus-Operatoren zu unterscheiden.
Sie können auch Tilde- und Nicht- (!) unäre Methoden mit @ versehen, dies ist jedoch nicht erforderlich, da es keine binären Tilde- und Nicht-Operatoren gibt.
Unäre Methoden akzeptieren keine Argumente.
Zusätzlich können Methoden für Elementreferenz und Zuweisung definiert werden: [] bzw. []=. Beide können ein oder mehrere Argumente annehmen, und die Elementreferenz kann keines annehmen.
class C def [](a, b) puts a + b end def []=(a, b, c) puts a * b + c end end obj = C.new obj[2, 3] # prints "5" obj[2, 3] = 4 # prints "10"
Rückgabewerte
Standardmäßig gibt eine Methode den letzten ausgewerteten Ausdruck im Körper der Methode zurück. Im obigen Beispiel war der letzte (und einzige) ausgewertete Ausdruck die einfache Summe 1 + 1. Das Schlüsselwort return kann verwendet werden, um explizit zu machen, dass eine Methode einen Wert zurückgibt.
def one_plus_one return 1 + 1 end
Es kann auch verwendet werden, um eine Methode zurückzugeben, bevor der letzte Ausdruck ausgewertet wird.
def two_plus_two return 2 + 2 1 + 1 # this expression is never evaluated end
Beachten Sie, dass bei Zuweisungsmethoden der Rückgabewert bei Verwendung der Zuweisungssyntax ignoriert wird. Stattdessen wird das Argument zurückgegeben
def a=(value) return 1 + value end p(self.a = 5) # prints 5
Der tatsächliche Rückgabewert wird bei direktem Aufruf der Methode zurückgegeben
p send(:a=, 5) # prints 6
Scope
Die Standard-Syntax zur Definition einer Methode
def my_method # ... end
fügt die Methode einer Klasse hinzu. Sie können eine Instanzmethode für eine bestimmte Klasse mit dem Schlüsselwort class definieren
class C def my_method # ... end end
Eine Methode kann auf einem anderen Objekt definiert werden. Sie können eine "Klassenmethode" (eine Methode, die auf der Klasse und nicht auf einer Instanz der Klasse definiert ist) wie folgt definieren
class C def self.my_method # ... end end
Dies ist jedoch lediglich ein Sonderfall einer größeren syntaktischen Leistung in Ruby, der Fähigkeit, Methoden zu jedem Objekt hinzuzufügen. Klassen sind Objekte, daher ist das Hinzufügen von Klassenmethoden einfach das Hinzufügen von Methoden zum Klassenobjekt.
Die Syntax zum Hinzufügen einer Methode zu einem Objekt lautet wie folgt
greeting = "Hello" def greeting.broaden self + ", world!" end greeting.broaden # returns "Hello, world!"
self ist ein Schlüsselwort, das sich auf das aktuelle Objekt bezieht, das vom Compiler betrachtet wird, was die Verwendung von self bei der Definition einer Klassenmethode oben etwas klarer machen kann. Tatsächlich kann das Beispiel des Hinzufügens einer hello-Methode zur Klasse String wie folgt umgeschrieben werden
def String.hello "Hello, world!" end
Eine auf diese Weise definierte Methode wird als "Singleton-Methode" bezeichnet. broaden existiert nur für die String-Instanz greeting. Andere Strings werden broaden nicht haben.
Überschreiben
Wenn Ruby auf das Schlüsselwort def stößt, betrachtet es dies nicht als Fehler, wenn die Methode bereits existiert: es definiert sie einfach neu. Dies wird als *Überschreiben* bezeichnet. Ähnlich wie das Erweitern von Kernklassen ist dies eine potenziell gefährliche Fähigkeit und sollte sparsam eingesetzt werden, da sie zu unerwarteten Ergebnissen führen kann. Betrachten Sie zum Beispiel diese irb-Sitzung
>> "43".to_i => 43 >> class String >> def to_i >> 42 >> end >> end => nil >> "43".to_i => 42
Dies wird effektiv jeglichen Code sabotieren, der die Methode String#to_i zum Parsen von Zahlen aus Strings verwendet.
Argumente
Eine Methode kann Argumente akzeptieren. Die Argumentliste folgt dem Methodennamen
def add_one(value) value + 1 end
Beim Aufruf muss der Benutzer der add_one-Methode ein Argument bereitstellen. Das Argument ist eine lokale Variable im Methodenkörper. Die Methode addiert dann eins zu diesem Argument und gibt den Wert zurück. Wenn 1 übergeben wird, gibt diese Methode 2 zurück.
Die Klammern um die Argumente sind optional
def add_one value value + 1 end
Die Klammern sind bei Kurzschreibweisen für Methoden obligatorisch
# OK def add_one(value) = value + 1 # SyntaxError def add_one value = value + 1
Mehrere Argumente werden durch ein Komma getrennt
def add_values(a, b) a + b end
Beim Aufruf müssen die Argumente in der exakten Reihenfolge bereitgestellt werden. Mit anderen Worten, die Argumente sind positional.
Standardwerte
Argumente können Standardwerte haben
def add_values(a, b = 1) a + b end
Der Standardwert muss nicht zuerst erscheinen, aber Argumente mit Standardwerten müssen zusammen gruppiert werden. Das ist in Ordnung
def add_values(a = 1, b = 2, c) a + b + c end
Dies löst einen SyntaxError aus
def add_values(a = 1, b, c = 1) a + b + c end
Standardargumentwerte können sich auf Argumente beziehen, die bereits als lokale Variablen ausgewertet wurden, und Argumentwerte werden immer von links nach rechts ausgewertet. Daher ist dies zulässig
def add_values(a = 1, b = a) a + b end add_values # => 2
Dies löst jedoch einen NameError aus (es sei denn, es gibt eine Methode namens b, die definiert ist)
def add_values(a = b, b = 1) a + b end add_values # NameError (undefined local variable or method `b' for main:Object)
Array-Dekompression
Sie können ein Array dekomprimieren (entpacken oder Werte extrahieren) mithilfe zusätzlicher Klammern in den Argumenten
def my_method((a, b)) p a: a, b: b end my_method([1, 2])
Dies gibt aus:
{:a=>1, :b=>2}
Wenn das Argument zusätzliche Elemente im Array hat, werden diese ignoriert
def my_method((a, b)) p a: a, b: b end my_method([1, 2, 3])
Dies hat die gleiche Ausgabe wie oben.
Sie können einen * verwenden, um die restlichen Argumente zu sammeln. Dies teilt ein Array in ein erstes Element und den Rest auf
def my_method((a, *b)) p a: a, b: b end my_method([1, 2, 3])
Dies gibt aus:
{:a=>1, :b=>[2, 3]}
Das Argument wird dekomprimiert, wenn es auf to_ary antwortet. Sie sollten to_ary nur definieren, wenn Sie Ihr Objekt anstelle eines Array verwenden können.
Die Verwendung der inneren Klammern verwendet nur eines der übergebenen Argumente. Wenn das Argument kein Array ist, wird es dem ersten Argument in der Dekompression zugewiesen und die restlichen Argumente in der Dekompression sind nil
def my_method(a, (b, c), d) p a: a, b: b, c: c, d: d end my_method(1, 2, 3)
Dies gibt aus:
{:a=>1, :b=>2, :c=>nil, :d=>3}
Sie können die Dekompression beliebig verschachteln
def my_method(((a, b), c)) # ... end
Array/Hash-Argument
Das Präfix eines Arguments mit * bewirkt, dass alle verbleibenden Argumente in ein Array konvertiert werden
def gather_arguments(*arguments) p arguments end gather_arguments 1, 2, 3 # prints [1, 2, 3]
Das Array-Argument muss vor allen Schlüsselwortargumenten erscheinen.
Es ist möglich, Argumente am Anfang oder in der Mitte zu sammeln
def gather_arguments(first_arg, *middle_arguments, last_arg) p middle_arguments end gather_arguments 1, 2, 3, 4 # prints [2, 3]
Das Array-Argument erfasst einen Hash als letzten Eintrag, wenn Schlüsselwörter vom Aufrufer nach allen Positionsargumenten bereitgestellt wurden.
def gather_arguments(*arguments) p arguments end gather_arguments 1, a: 2 # prints [1, {:a=>2}]
Dies geschieht jedoch nur, wenn die Methode keine Schlüsselwortargumente deklariert.
def gather_arguments_keyword(*positional, keyword: nil) p positional: positional, keyword: keyword end gather_arguments_keyword 1, 2, three: 3 #=> raises: unknown keyword: three (ArgumentError)
Beachten Sie auch, dass ein nacktes * verwendet werden kann, um Argumente zu ignorieren
def ignore_arguments(*) end
Sie können auch ein nacktes * beim Aufrufen einer Methode verwenden, um die Argumente direkt an eine andere Methode weiterzugeben
def delegate_arguments(*) other_method(*) end
Schlüsselwortargumente
Schlüsselwortargumente sind ähnlich wie Positionsargumente mit Standardwerten
def add_values(first: 1, second: 2) first + second end
Beliebige Schlüsselwortargumente werden mit ** akzeptiert
def gather_arguments(first: nil, **rest) p first, rest end gather_arguments first: 1, second: 2, third: 3 # prints 1 then {:second=>2, :third=>3}
Beim Aufrufen einer Methode mit Schlüsselwortargumenten können die Argumente in beliebiger Reihenfolge erscheinen. Wenn vom Aufrufer ein unbekanntes Schlüsselwortargument gesendet wird und die Methode keine beliebigen Schlüsselwortargumente akzeptiert, wird ein ArgumentError ausgelöst.
Um ein bestimmtes Schlüsselwortargument zu erzwingen, fügen Sie dem Schlüsselwortargument keinen Standardwert hinzu
def add_values(first:, second:) first + second end add_values # ArgumentError (missing keywords: first, second) add_values(first: 1, second: 2) # => 3
Beim Mischen von Schlüsselwortargumenten und Positionsargumenten müssen alle Positionsargumente vor allen Schlüsselwortargumenten erscheinen.
Beachten Sie auch, dass ** verwendet werden kann, um Schlüsselwortargumente zu ignorieren
def ignore_keywords(**) end
Sie können ** auch beim Aufrufen einer Methode verwenden, um Schlüsselwortargumente an eine andere Methode weiterzuleiten
def delegate_keywords(**) other_method(**) end
Um eine Methode als Schlüsselwörter akzeptierend zu markieren, aber keine Schlüsselwörter zu akzeptieren, können Sie **nil verwenden
def no_keywords(**nil) end
Das Aufrufen einer solchen Methode mit Schlüsselwörtern oder einem nicht leeren Schlüsselwort-Splat führt zu einem ArgumentError. Diese Syntax wird unterstützt, damit Schlüsselwörter später zur Methode hinzugefügt werden können, ohne die Abwärtskompatibilität zu beeinträchtigen.
Wenn eine Methodendefinition keine Schlüsselwörter akzeptiert und die **nil-Syntax nicht verwendet wird, werden alle beim Aufruf der Methode bereitgestellten Schlüsselwörter in ein Positionsargument des Typs Hash konvertiert
def meth(arg) arg end meth(a: 1) # => {:a=>1}
Block-Argument
Das Block-Argument wird durch & gekennzeichnet und muss zuletzt kommen
def my_method(&my_block) my_block.call(self) end
Am häufigsten wird das Block-Argument verwendet, um einen Block an eine andere Methode zu übergeben
def each_item(&block) @items.each(&block) end
Sie müssen dem Block keinen Namen geben, wenn Sie ihn nur an eine andere Methode übergeben werden
def each_item(&) @items.each(&) end
Wenn Sie den Block nur aufrufen und ihn nicht anderweitig manipulieren oder an eine andere Methode senden, wird die Verwendung von yield ohne expliziten Blockparameter bevorzugt. Diese Methode ist äquivalent zur ersten Methode in diesem Abschnitt
def my_method yield self end
Argumentweiterleitung
Seit Ruby 2.7 gibt es eine Syntax für die Weiterleitung aller Argumente
def concrete_method(*positional_args, **keyword_args, &block) [positional_args, keyword_args, block] end def forwarding_method(...) concrete_method(...) end forwarding_method(1, b: 2) { puts 3 } #=> [[1], {:b=>2}, #<Proc:...skip...>]
Das Aufrufen mit Weiterleitung ... ist nur in Methoden verfügbar, die mit ... definiert sind.
def regular_method(arg, **kwarg) concrete_method(...) # Syntax error end
Seit Ruby 3.0 können sowohl in Definitionen als auch in Aufrufen führende Argumente vor ... stehen (aber in Definitionen können dies nur Positionsargumente ohne Standardwerte sein).
def request(method, path, **headers) puts "#{method.upcase} #{path} #{headers}" end def get(...) request(:GET, ...) # leading argument in invoking end get('https://ruby-lang.de', 'Accept' => 'text/html') # Prints: GET https://ruby-lang.de {"Accept"=>"text/html"} def logged_get(msg, ...) # leading argument in definition puts "Invoking #get: #{msg}" get(...) end logged_get('Ruby site', 'https://ruby-lang.de') # Prints: # Invoking #get: Ruby site # GET https://ruby-lang.de {}
Beachten Sie, dass das Weglassen von Klammern bei Weiterleitungsaufrufen zu unerwarteten Ergebnissen führen kann
def log(...) puts ... # This would be treated as `puts()...', # i.e. endless range from puts result end log("test") # Prints: warning: ... at EOL, should be parenthesized? # ...and then empty line
Exception-Behandlung
Methoden haben einen impliziten Ausnahmebehandlungsblock, sodass Sie begin oder end nicht zur Ausnahmebehandlung verwenden müssen. Dies
def my_method begin # code that may raise an exception rescue # handle exception end end
Kann geschrieben werden als
def my_method # code that may raise an exception rescue # handle exception end
Ähnlich können Sie, wenn Sie Code immer ausführen möchten, auch wenn eine Ausnahme ausgelöst wird, ensure ohne begin und end verwenden
def my_method # code that may raise an exception ensure # code that runs even if previous code raised an exception end
Sie können rescue auch mit ensure und/oder else kombinieren, ohne begin und end
def my_method # code that may raise an exception rescue # handle exception else # only run if no exception raised above ensure # code that runs even if previous code raised an exception end
Wenn Sie eine Ausnahme nur für einen Teil Ihrer Methode abfangen möchten, verwenden Sie begin und end. Weitere Details finden Sie auf der Seite zur Ausnahmebehandlung.