Zoeken…


Invoering

Functies in Ruby bieden georganiseerde, herbruikbare code om een reeks acties uit te voeren. Functies vereenvoudigen het coderingsproces, voorkomen overbodige logica en maken code eenvoudiger te volgen. Dit onderwerp beschrijft de verklaring en het gebruik van functies, argumenten, parameters, opbrengstverklaringen en bereik in Ruby.

Opmerkingen

Een methode is een benoemd codeblok, gekoppeld aan een of meer objecten en meestal geïdentificeerd door een lijst met parameters naast de naam.

def hello(name)
  "Hello, #{name}"
end

Een methode-aanroep specificeert de methode-naam, het object waarop deze moet worden aangeroepen (soms de ontvanger genoemd) en nul of meer argumentwaarden die zijn toegewezen aan de genoemde methode-parameters. De waarde van de laatste uitdrukking die in de methode is geëvalueerd, wordt de waarde van de methode-aanroepingsexpressie.

hello("World")
# => "Hello, World"

Wanneer de ontvanger niet expliciet is, is hij self .

self
# => main

self.hello("World")
# => "Hello, World"

Zoals uitgelegd in het Ruby Programming Language- boek, maken veel talen onderscheid tussen functies, waaraan geen object is gekoppeld, en methoden die op een ontvangerobject worden aangeroepen. Omdat Ruby een puur objectgeoriënteerde taal is, zijn alle methoden echte methoden en worden ze geassocieerd met ten minste één object.

Overzicht van methodeparameters

Type Methode handtekening Oproepvoorbeeld opdrachten
R gelijkgesteld def fn(a,b,c) fn(2,3,5) a=2, b=3, c=5
V ariadisch 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 oogwoord def fn(a:0,b:1) fn(a:2,b:3) a=2, b=3

Deze argumenttypen kunnen op vrijwel elke manier worden gecombineerd om variadische functies te maken. Het minimumaantal argumenten voor de functie is gelijk aan het aantal vereiste argumenten in de handtekening. Extra argumenten worden eerst toegewezen aan standaardparameters en vervolgens aan de parameter *rest .

Type Methode handtekening Oproepvoorbeeld opdrachten
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}

Enkele vereiste parameter

def say_hello_to(name)
    puts "Hello #{name}"
end

say_hello_to('Charles')    # Hello Charles

Meerdere vereiste parameters

def greet(greeting, name)
    puts "#{greeting} #{name}"
end

greet('Hi', 'Sophie')    # Hi Sophie

Standaard parameters

def make_animal_sound(sound = 'Cuack')
    puts sound
end

make_animal_sound('Mooo') # Mooo
make_animal_sound         # Cuack

Het is mogelijk om standaardwaarden op te nemen voor meerdere argumenten:

def make_animal_sound(sound = 'Cuack', volume = 11)
    play_sound(sound, volume)
end

make_animal_sound('Mooo') # Spinal Tap cow

Het is echter niet mogelijk om de tweede te leveren zonder ook de eerste te leveren. Probeer in plaats van positionele parameters te gebruiken, trefwoordparameters:

def make_animal_sound(sound: 'Cuack', volume: 11)
    play_sound(sound, volume)
end

make_animal_sound(volume: 1) # Duck whisper

Of een hash-parameter die opties opslaat:

def make_animal_sound(options = {})
    options[:sound]  ||= 'Cuak'
    options[:volume] ||= 11
    play_sound(sound, volume)
end

make_animal_sound(:sound => 'Mooo') 

Standaard parameterwaarden kunnen worden ingesteld met elke robijnrode uitdrukking. De uitdrukking wordt uitgevoerd in de context van de methode, dus u kunt hier zelfs lokale variabelen opgeven. Let op, komt niet door code review. Met dank aan Caius voor het wijzen hierop .

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)

Optionele parameter (s) (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!

Merk op dat welcome_guests(['Rob', 'Sally', 'Lucas']) Welcome ["Rob", "Sally", "Lucas"]!
In plaats daarvan, als je een lijst hebt, kun je welcome_guests(*['Rob', 'Sally', 'Lucas']) doen welcome_guests(*['Rob', 'Sally', 'Lucas']) en dat zal werken als welcome_guests('Rob', 'Sally', 'Lucas') .

Vereiste standaard optionele parameter mix

def my_mix(name,valid=true, *opt)
    puts name
    puts valid
    puts opt
end

Bel als volgt:

my_mix('me')
# 'me'
# true
# []

my_mix('me', false)
# 'me'
# false
# []

my_mix('me', true, 5, 7) 
# 'me'
# true
# [5,7]

Methodedefinities zijn uitdrukkingen

Als u een methode definieert in Ruby 2.x, wordt een symbool geretourneerd dat de naam vertegenwoordigt:

class Example
  puts def hello
  end
end

#=> :hello

Dit maakt interessante metaprogrammeringstechnieken mogelijk. Methoden kunnen bijvoorbeeld op andere manieren worden ingepakt:

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.

Niet-aangegeven trefwoordargumenten vastleggen (dubbele splat)

De ** operator werkt op dezelfde manier als de * operator maar is van toepassing op trefwoordparameters.

def options(required_key:, optional_key: nil, **other_options)
  other_options
end

options(required_key: 'Done!', foo: 'Foo!', bar: 'Bar!')
#> { :foo => "Foo!", :bar => "Bar!" }

In het bovenstaande voorbeeld, als de **other_options niet wordt gebruikt, zou een ArgumentError: unknown keyword: foo, bar **other_options worden opgeworpen.

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

Dit is handig als u een aantal opties hebt die u aan een methode wilt doorgeven en u de toetsen niet wilt filteren.

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!" }

Het is ook mogelijk om een hash uit te pakken met de ** operator. Hiermee kunt u trefwoorden direct aan een methode toevoegen naast waarden uit andere hashes:

my_hash = { foo: 'Foo!', bar: 'Bar!' }

options(required_key: true, **my_hash)
#> { :foo => "Foo!", :bar => "Bar!" }

Opbrengst aan blokken

U kunt een blok naar uw methode verzenden en het kan dat blok meerdere keren aanroepen. Dit kan worden gedaan door een proc / lambda of iets dergelijks te sturen, maar is gemakkelijker en sneller met yield :

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

Merk op dat de { puts ... } niet tussen haakjes staat, maar impliciet volgt. Dit betekent ook dat we slechts één yield kunnen hebben. We kunnen argumenten doorgeven aan de 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

Met opbrengst kunnen we gemakkelijk iterators maken of andere functies die op andere code werken:

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 feite is het met yield dat dingen als foreach each times in het algemeen in klassen worden geïmplementeerd.

Als je wilt weten of je een blok hebt gekregen of niet, gebruik dan 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 dit voorbeeld wordt ervan uitgegaan dat de klasse Employees een @employees die met each kan worden herhaald om objecten met de name werknemer op te halen. Als we een blok krijgen, dan zullen we yield de naam het blok, anders duwen we gewoon aan een array die we terugkeren.

Tuple Argumenten

Een methode kan een matrixparameter nemen en deze onmiddellijk in benoemde lokale variabelen vernietigen. Gevonden op het blog van Mathias Meyer .

def feed( amount, (animal, food) )

    p "#{amount} #{animal}s chew some #{food}"

end

feed 3, [ 'rabbit', 'grass' ] # => "3 rabbits chew some grass"

Een methode definiëren

Methoden worden gedefinieerd met het sleutelwoord def , gevolgd door de methode naam en een optionele lijst met parameternamen tussen haakjes. De Ruby-code tussen def en end vertegenwoordigt de body van de methode.

def hello(name)
  "Hello, #{name}"
end

Een methode-aanroep specificeert de methode-naam, het object waarop deze moet worden aangeroepen (soms de ontvanger genoemd) en nul of meer argumentwaarden die zijn toegewezen aan de genoemde methode-parameters.

hello("World")
# => "Hello, World"

Wanneer de ontvanger niet expliciet is, is hij self .

Parameternamen kunnen worden gebruikt als variabelen in de methode en de waarden van deze benoemde parameters komen uit de argumenten voor een methode-aanroep.

hello("World")
# => "Hello, World"
hello("All")
# => "Hello, All"

Gebruik een functie als blok

Veel functies in Ruby accepteren een blok als argument. bv:

[0, 1, 2].map {|i| i + 1}
 => [1, 2, 3]

Als je al een functie hebt die doet wat je wilt, kun je deze met behulp van &method(:fn) in een blok veranderen:

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
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow