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]


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow