Ruby Language
Methoden
Suche…
Einführung
Funktionen in Ruby stellen organisierten, wiederverwendbaren Code bereit, um eine Reihe von Aktionen auszuführen. Funktionen vereinfachen den Codierungsprozess, verhindern redundante Logik und machen Code leichter nachvollziehbar. In diesem Thema werden die Deklaration und Verwendung von Funktionen, Argumenten, Parametern, Ertragsanweisungen und Geltungsbereich in Ruby beschrieben.
Bemerkungen
Eine Methode ist ein benannter Codeblock, der einem oder mehreren Objekten zugeordnet ist und im Allgemeinen durch eine Liste von Parametern zusätzlich zum Namen gekennzeichnet wird.
def hello(name)
"Hello, #{name}"
end
Ein Methodenaufruf gibt den Methodennamen, das Objekt an, für das er aufgerufen werden soll (manchmal als Empfänger bezeichnet) und null oder mehr Argumentwerte, die den benannten Methodenparametern zugewiesen werden. Der Wert des letzten in der Methode bewerteten Ausdrucks wird zum Wert des Methodenaufrufausdrucks.
hello("World")
# => "Hello, World"
Wenn der Empfänger nicht explizit ist, ist er self
.
self
# => main
self.hello("World")
# => "Hello, World"
Wie im Ruby Programming Language- Buch erläutert, unterscheiden viele Sprachen zwischen Funktionen, denen kein Objekt zugeordnet ist, und Methoden, die für ein Empfängerobjekt aufgerufen werden. Da Ruby eine rein objektorientierte Sprache ist, sind alle Methoden echte Methoden und werden mit mindestens einem Objekt verknüpft.
Überblick über Methodenparameter
Art | Method Signatur | Rufen Sie ein Beispiel an | Zuordnungen |
---|---|---|---|
R gleichgestellt | def fn(a,b,c) | fn(2,3,5) | a=2, b=3, c=5 |
V ariadic | def fn(*rest) | fn(2,3,5) | rest=[2, 3, 5] |
D efault | def fn(a=0,b=1) | fn(2,3) | a=2, b=3 |
K Augenwort | def fn(a:0,b:1) | fn(a:2,b:3) | a=2, b=3 |
Diese Argumenttypen können auf praktisch jede Art und Weise kombiniert werden, um Variadic-Funktionen zu erstellen. Die Mindestanzahl von Argumenten für die Funktion entspricht der Anzahl der erforderlichen Argumente in der Signatur. Zusätzliche Argumente werden zuerst den Standardparametern zugewiesen, dann dem Parameter *rest
.
Art | Method Signatur | Rufen Sie ein Beispiel an | Zuordnungen |
---|---|---|---|
R, D, V, R | def fn(a,b=1,*mid,z) | fn(2,97) | a=2, b=1, mid=[], z=97 |
fn(2,3,97) | a=2, b=3, mid=[], z=97 | ||
fn(2,3,5,97) | a=2, b=3, mid=[5], z=97 | ||
fn(2,3,5,7,97) | a=2, b=3, mid=[5,7], z=97 | ||
R, K, K | def fn(a,g:6,h:7) | fn(2) | a=2, g=6, h=7 |
fn(2,h:19) | a=2, g=6, h=19 | ||
fn(2,g:17,h:19) | a=2, g=17, h=19 | ||
VK | def fn(**ks) | fn(a:2,g:17,h:19) | ks={a:2, g:17, h:19} |
fn(four:4,five:5) | ks={four:4, five:5} |
Einzelner erforderlicher Parameter
def say_hello_to(name)
puts "Hello #{name}"
end
say_hello_to('Charles') # Hello Charles
Mehrere erforderliche Parameter
def greet(greeting, name)
puts "#{greeting} #{name}"
end
greet('Hi', 'Sophie') # Hi Sophie
Standardparameter
def make_animal_sound(sound = 'Cuack')
puts sound
end
make_animal_sound('Mooo') # Mooo
make_animal_sound # Cuack
Es ist möglich, Standardwerte für mehrere Argumente anzugeben:
def make_animal_sound(sound = 'Cuack', volume = 11)
play_sound(sound, volume)
end
make_animal_sound('Mooo') # Spinal Tap cow
Es ist jedoch nicht möglich, die zweite zu liefern, ohne auch die erste zu liefern. Versuchen Sie anstelle von Positionsparametern die Schlüsselwortparameter:
def make_animal_sound(sound: 'Cuack', volume: 11)
play_sound(sound, volume)
end
make_animal_sound(volume: 1) # Duck whisper
Oder ein Hash-Parameter, der Optionen speichert:
def make_animal_sound(options = {})
options[:sound] ||= 'Cuak'
options[:volume] ||= 11
play_sound(sound, volume)
end
make_animal_sound(:sound => 'Mooo')
Standardparameterwerte können durch einen beliebigen Ruby-Ausdruck festgelegt werden. Der Ausdruck wird im Kontext der Methode ausgeführt, sodass Sie hier sogar lokale Variablen deklarieren können. Beachten Sie, dass der Code nicht durchlaufen wird. Mit freundlicher Genehmigung von caius für diesen Hinweis .
def make_animal_sound( sound = ( raise 'TUU-too-TUU-too...' ) ); p sound; end
make_animal_sound 'blaaaa' # => 'blaaaa'
make_animal_sound # => TUU-too-TUU-too... (RuntimeError)
Optionale Parameter (Splat-Operator)
def welcome_guests(*guests)
guests.each { |guest| puts "Welcome #{guest}!" }
end
welcome_guests('Tom') # Welcome Tom!
welcome_guests('Rob', 'Sally', 'Lucas') # Welcome Rob!
# Welcome Sally!
# Welcome Lucas!
Beachten Sie, dass welcome_guests(['Rob', 'Sally', 'Lucas'])
Welcome ["Rob", "Sally", "Lucas"]!
ausgeben wird Welcome ["Rob", "Sally", "Lucas"]!
Wenn Sie jedoch eine Liste haben, können Sie welcome_guests(*['Rob', 'Sally', 'Lucas'])
welcome_guests('Rob', 'Sally', 'Lucas')
und diese Funktion funktioniert als welcome_guests('Rob', 'Sally', 'Lucas')
.
Erforderlicher Standardmix für optionale Parameter
def my_mix(name,valid=true, *opt)
puts name
puts valid
puts opt
end
Rufen Sie wie folgt an:
my_mix('me')
# 'me'
# true
# []
my_mix('me', false)
# 'me'
# false
# []
my_mix('me', true, 5, 7)
# 'me'
# true
# [5,7]
Methodendefinitionen sind Ausdrücke
Das Definieren einer Methode in Ruby 2.x gibt ein Symbol zurück, das den Namen darstellt:
class Example
puts def hello
end
end
#=> :hello
Dies ermöglicht interessante Metaprogrammiertechniken. Zum Beispiel können Methoden von anderen Methoden umschlossen werden:
class Class
def logged(name)
original_method = instance_method(name)
define_method(name) do |*args|
puts "Calling #{name} with #{args.inspect}."
original_method.bind(self).call(*args)
puts "Completed #{name}."
end
end
end
class Meal
def initialize
@food = []
end
logged def add(item)
@food << item
end
end
meal = Meal.new
meal.add "Coffee"
# Calling add with ["Coffee"].
# Completed add.
Nicht deklarierte Schlüsselwort-Argumente erfassen (Doppel-Splat)
Der Operator **
arbeitet ähnlich wie der Operator *
, gilt jedoch für Schlüsselwortparameter.
def options(required_key:, optional_key: nil, **other_options)
other_options
end
options(required_key: 'Done!', foo: 'Foo!', bar: 'Bar!')
#> { :foo => "Foo!", :bar => "Bar!" }
Wenn im obigen Beispiel **other_options
nicht verwendet wird, wird ein ArgumentError: unknown keyword: foo, bar
error **other_options
.
def without_double_splat(required_key:, optional_key: nil)
# do nothing
end
without_double_splat(required_key: 'Done!', foo: 'Foo!', bar: 'Bar!')
#> ArgumentError: unknown keywords: foo, bar
Dies ist praktisch, wenn Sie einen Hash von Optionen haben, die Sie an eine Methode übergeben möchten, und Sie die Schlüssel nicht filtern möchten.
def options(required_key:, optional_key: nil, **other_options)
other_options
end
my_hash = { required_key: true, foo: 'Foo!', bar: 'Bar!' }
options(my_hash)
#> { :foo => "Foo!", :bar => "Bar!" }
Es ist auch möglich, einen Hash mit dem Operator **
zu entpacken . Auf diese Weise können Sie einer Methode zusätzlich zu Werten aus anderen Hashwerten direkt ein Schlüsselwort bereitstellen:
my_hash = { foo: 'Foo!', bar: 'Bar!' }
options(required_key: true, **my_hash)
#> { :foo => "Foo!", :bar => "Bar!" }
Nachgebende Blöcke
Sie können einen Block an Ihre Methode senden und den Block mehrmals aufrufen. Dies kann durch Senden eines proc / lambda oder dergleichen erfolgen, ist jedoch mit der yield
einfacher und schneller:
def simple(arg1,arg2)
puts "First we are here: #{arg1}"
yield
puts "Finally we are here: #{arg2}"
yield
end
simple('start','end') { puts "Now we are inside the yield" }
#> First we are here: start
#> Now we are inside the yield
#> Finally we are here: end
#> Now we are inside the yield
Beachten Sie, dass { puts ... }
nicht in den Klammern steht, sondern implizit danach. Dies bedeutet auch, dass wir nur einen yield
. Wir können Argumente an die yield
:
def simple(arg)
puts "Before yield"
yield(arg)
puts "After yield"
end
simple('Dave') { |name| puts "My name is #{name}" }
#> Before yield
#> My name is Dave
#> After yield
Mit Yield können wir leicht Iteratoren oder Funktionen erstellen, die mit anderem Code funktionieren:
def countdown(num)
num.times do |i|
yield(num-i)
end
end
countdown(5) { |i| puts "Call number #{i}" }
#> Call number 5
#> Call number 4
#> Call number 3
#> Call number 2
#> Call number 1
In der Tat ist es mit yield
, die Dinge wie foreach
, each
und times
sind in der Regel in Klassen implementiert.
Wenn Sie herausfinden möchten, ob Sie einen Block erhalten haben oder nicht, verwenden Sie block_given?
:
class Employees
def names
ret = []
@employees.each do |emp|
if block_given?
yield(emp.name)
else
ret.push(emp.name)
end
end
ret
end
end
In diesem Beispiel wird davon @employees
, dass die Employees
Klasse über eine @employees
Liste verfügt, die mit each
iteriert each
, um Objekte mit Personennamen mithilfe der name
Methode @employees
. Wenn wir einen Block gegeben sind, dann werden wir yield
den Namen auf den Block, sonst wir es nur drücken , um ein Array , das wir zurückkehren.
Tuple Argumente
Eine Methode kann einen Array-Parameter übernehmen und sofort in benannte lokale Variablen zerstören. Gefunden im Blog von Mathias Meyer .
def feed( amount, (animal, food) )
p "#{amount} #{animal}s chew some #{food}"
end
feed 3, [ 'rabbit', 'grass' ] # => "3 rabbits chew some grass"
Methode definieren
Methoden werden mit dem Schlüsselwort def
definiert, gefolgt vom Methodennamen und einer optionalen Liste von Parameternamen in Klammern. Der Ruby-Code zwischen def
und end
repräsentiert den Rumpf der Methode.
def hello(name)
"Hello, #{name}"
end
Ein Methodenaufruf gibt den Methodennamen, das Objekt an, für das er aufgerufen werden soll (manchmal als Empfänger bezeichnet) und null oder mehr Argumentwerte, die den benannten Methodenparametern zugewiesen werden.
hello("World")
# => "Hello, World"
Wenn der Empfänger nicht explizit ist, ist er self
.
Parameternamen können als Variablen innerhalb des Methodenkörpers verwendet werden, und die Werte dieser benannten Parameter stammen von den Argumenten für einen Methodenaufruf.
hello("World")
# => "Hello, World"
hello("All")
# => "Hello, All"
Verwenden Sie eine Funktion als Block
Viele Funktionen in Ruby akzeptieren einen Block als Argument. Z.B:
[0, 1, 2].map {|i| i + 1}
=> [1, 2, 3]
Wenn Sie bereits eine Funktion haben, die das tut, was Sie möchten, können Sie sie mit der &method(:fn)
in einen Block &method(:fn)
:
def inc(num)
num + 1
end
[0, 1, 2].map &method(:inc)
=> [1, 2, 3]