Sök…


Introduktion

Funktioner i Ruby tillhandahåller organiserad, återanvändbar kod för att förforma en uppsättning åtgärder. Funktioner förenklar kodningsprocessen, förhindrar redundant logik och gör koden lättare att följa. Det här ämnet beskriver deklarationen och användningen av funktioner, argument, parametrar, avkastningsförklaringar och omfattning i Ruby.

Anmärkningar

En metod är ett namngivet kodblock, associerat med ett eller flera objekt och generellt identifieras av en lista med parametrar utöver namnet.

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

En metodinkallation anger metodnamnet, objektet som det ska anropas (ibland kallat mottagaren) och noll eller fler argumentvärden som tilldelas de nämnda metodparametrarna. Värdet på det sista uttrycket som utvärderas i metoden blir värdet på metodens invokationsuttryck.

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

När mottagaren inte är uttrycklig är den self .

self
# => main

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

Som förklarats i Ruby Programming Language- boken skiljer många språk mellan funktioner, som inte har något associerat objekt, och metoder, som åberopas på ett mottagarobjekt. Eftersom Ruby är ett rent objektorienterat språk är alla metoder verkliga metoder och är associerade med minst ett objekt.

Översikt över metodparametrar

Typ Metodunderskrift Ring exempel Uppgifter
R utjämnade def fn(a,b,c) fn(2,3,5) a=2, b=3, c=5
V ariadisk 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 eyword def fn(a:0,b:1) fn(a:2,b:3) a=2, b=3

Dessa argumenttyper kan kombineras på nästan vilket sätt du kan tänka dig att skapa variadiska funktioner. Det minsta antalet argument för funktionen kommer att motsvara mängden nödvändiga argument i signaturen. Extra argument tilldelas först standardparametrar och sedan till *rest viloparametern.

Typ Metodunderskrift Ring exempel Uppgifter
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}

Enskild parameter

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

say_hello_to('Charles')    # Hello Charles

Flera nödvändiga parametrar

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

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

Standardparametrar

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

make_animal_sound('Mooo') # Mooo
make_animal_sound         # Cuack

Det är möjligt att inkludera standardvärden för flera argument:

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

make_animal_sound('Mooo') # Spinal Tap cow

Det är dock inte möjligt att leverera den andra utan att också leverera den första. Istället för att använda positionsparametrar, prova nyckelordsparametrar:

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

make_animal_sound(volume: 1) # Duck whisper

Eller en hash-parameter som lagrar alternativ:

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

make_animal_sound(:sound => 'Mooo') 

Standardparametervärden kan ställas in med valfritt rubinuttryck. Uttrycket körs i samband med metoden, så att du till och med kan deklara lokala variabler här. Observera att du inte kommer igenom kodgranskningen. Med tillstånd av caius för att påpeka detta .

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)

Valfri parameter (er) (splat-operatör)

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!

Observera att welcome_guests(['Rob', 'Sally', 'Lucas']) kommer att producera Welcome ["Rob", "Sally", "Lucas"]!
Istället, om du har en lista, kan du göra welcome_guests(*['Rob', 'Sally', 'Lucas']) och det fungerar som welcome_guests('Rob', 'Sally', 'Lucas') .

Obligatorisk standardalternativmix

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

Ring enligt följande:

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

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

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

Metoddefinitioner är uttryck

Att definiera en metod i Ruby 2.x returnerar en symbol som representerar namnet:

class Example
  puts def hello
  end
end

#=> :hello

Detta möjliggör intressanta metaprogrammeringstekniker. Till exempel kan metoder lindas med andra metoder:

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.

Fånga odeklarerade sökordargument (dubbel splatt)

Operatören ** fungerar på samma sätt som operatören * men det gäller sökordsparametrar.

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

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

I exemplet ovan, om **other_options inte används, skulle ett ArgumentError: unknown keyword: foo, bar stapelfel tas upp.

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

Detta är praktiskt när du har en hash med alternativ som du vill överföra till en metod och du inte vill filtrera tangenterna.

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

Det är också möjligt att packa upp en hash med ** operatören. Detta gör att du kan leverera nyckelord direkt till en metod utöver värden från andra hash:

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

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

Avkastning till block

Du kan skicka ett block till din metod och det kan ringa det blocket flera gånger. Detta kan göras genom att skicka en proc / lambda eller så, men är enklare och snabbare med 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

Observera att { puts ... } inte finns inom parenteserna, det kommer implicit efter. Det betyder också att vi bara kan ha ett yield . Vi kan överföra argument till 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

Med avkastning kan vi enkelt göra iteratorer eller andra funktioner som fungerar med annan kod:

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

I själva verket är det med yield som saker som foreach , each times allmänhet implementeras i klasser.

Om du vill ta reda på om du har fått ett block eller inte, använd 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

Detta exempel förutsätter att Employees klassen har en @employees lista som kan upprepas med each för att få objekt som har anställdas namn med hjälp av name metoden. Om vi får ett block, kommer vi att yield namnet till blocket, annars skjuter vi det bara till en matris som vi returnerar.

Tuple-argument

En metod kan ta en matrisparameter och förstöra den omedelbart i namngivna lokala variabler. Hittade på Mathias Meyers blogg .

def feed( amount, (animal, food) )

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

end

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

Definiera en metod

Metoder definieras med def nyckelordet, följt av metodnamnet och en valfri lista över parameternamn inom parentes. Rubinkoden mellan def och end representerar metodens kropp .

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

En metodinkallation anger metodnamnet, objektet som det ska anropas (ibland kallat mottagaren) och noll eller fler argumentvärden som tilldelas de nämnda metodparametrarna.

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

När mottagaren inte är uttrycklig är den self .

Parameternamn kan användas som variabler i metodkroppen, och värdena på dessa namngivna parametrar kommer från argumenten till en metodkallning.

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

Använd en funktion som ett block

Många funktioner i Ruby accepterar ett block som ett argument. T.ex:

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

Om du redan har en funktion som gör vad du vill kan du förvandla den till ett block med &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
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow