Ruby Language
metodi
Ricerca…
introduzione
Le funzioni in Ruby forniscono un codice organizzato e riutilizzabile per preformare un insieme di azioni. Le funzioni semplificano il processo di codifica, impediscono la logica ridondante e rendono il codice più facile da seguire. Questo argomento descrive la dichiarazione e l'utilizzo di funzioni, argomenti, parametri, dichiarazioni di rendimento e ambito in Ruby.
Osservazioni
Un metodo è un blocco di codice denominato, associato a uno o più oggetti e generalmente identificato da un elenco di parametri oltre al nome.
def hello(name)
"Hello, #{name}"
end
Un richiamo di metodo specifica il nome del metodo, l'oggetto su cui deve essere richiamato (talvolta chiamato il ricevente) e zero o più valori dell'argomento che sono assegnati ai parametri del metodo named. Il valore dell'ultima espressione valutata nel metodo diventa il valore dell'espressione di chiamata del metodo.
hello("World")
# => "Hello, World"
Quando il ricevitore non è esplicito, è un self
.
self
# => main
self.hello("World")
# => "Hello, World"
Come spiegato nel libro Ruby Programming Language , molte lingue distinguono tra funzioni, che non hanno oggetti associati e metodi, che sono invocati su un oggetto ricevente. Poiché Ruby è un linguaggio puramente orientato agli oggetti, tutti i metodi sono metodi veri e sono associati ad almeno un oggetto.
Panoramica dei parametri del metodo
genere | Metodo Signature | Esempio di chiamata | assegnazioni |
---|---|---|---|
R equo | 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 eyword | def fn(a:0,b:1) | fn(a:2,b:3) | a=2, b=3 |
Questi tipi di argomenti possono essere combinati praticamente in ogni modo possibile per creare funzioni variadiche. Il numero minimo di argomenti per la funzione sarà uguale alla quantità di argomenti richiesti nella firma. Gli argomenti extra verranno assegnati prima ai parametri predefiniti, quindi al parametro *rest
.
genere | Metodo Signature | Esempio di chiamata | assegnazioni |
---|---|---|---|
R, S, 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} |
Singolo parametro richiesto
def say_hello_to(name)
puts "Hello #{name}"
end
say_hello_to('Charles') # Hello Charles
Più parametri richiesti
def greet(greeting, name)
puts "#{greeting} #{name}"
end
greet('Hi', 'Sophie') # Hi Sophie
Parametri di default
def make_animal_sound(sound = 'Cuack')
puts sound
end
make_animal_sound('Mooo') # Mooo
make_animal_sound # Cuack
È possibile includere i valori predefiniti per più argomenti:
def make_animal_sound(sound = 'Cuack', volume = 11)
play_sound(sound, volume)
end
make_animal_sound('Mooo') # Spinal Tap cow
Tuttavia, non è possibile fornire il secondo senza fornire anche il primo. Invece di utilizzare i parametri posizionali, prova i parametri delle parole chiave:
def make_animal_sound(sound: 'Cuack', volume: 11)
play_sound(sound, volume)
end
make_animal_sound(volume: 1) # Duck whisper
O un parametro hash che memorizza le opzioni:
def make_animal_sound(options = {})
options[:sound] ||= 'Cuak'
options[:volume] ||= 11
play_sound(sound, volume)
end
make_animal_sound(:sound => 'Mooo')
I valori dei parametri predefiniti possono essere impostati da qualsiasi espressione di ruby. L'espressione verrà eseguita nel contesto del metodo, quindi puoi anche dichiarare le variabili locali qui. Nota, non passerà attraverso la revisione del codice. Per gentile concessione di caius per averlo indicato .
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)
Parametro opzionale (operatore splat)
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!
Nota che welcome_guests(['Rob', 'Sally', 'Lucas'])
mostrerà Welcome ["Rob", "Sally", "Lucas"]!
Invece, se hai una lista, puoi fare welcome_guests(*['Rob', 'Sally', 'Lucas'])
e funzionerà come welcome_guests('Rob', 'Sally', 'Lucas')
.
Mix di parametri facoltativo predefinito richiesto
def my_mix(name,valid=true, *opt)
puts name
puts valid
puts opt
end
Chiama come segue:
my_mix('me')
# 'me'
# true
# []
my_mix('me', false)
# 'me'
# false
# []
my_mix('me', true, 5, 7)
# 'me'
# true
# [5,7]
Le definizioni di metodo sono espressioni
La definizione di un metodo in Ruby 2.x restituisce un simbolo che rappresenta il nome:
class Example
puts def hello
end
end
#=> :hello
Ciò consente interessanti tecniche di metaprogrammazione. Ad esempio, i metodi possono essere impacchettati con altri metodi:
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.
Catturare argomenti di parole chiave non dichiarate (double splat)
L'operatore **
funziona in modo simile all'operatore *
ma si applica ai parametri delle parole chiave.
def options(required_key:, optional_key: nil, **other_options)
other_options
end
options(required_key: 'Done!', foo: 'Foo!', bar: 'Bar!')
#> { :foo => "Foo!", :bar => "Bar!" }
Nell'esempio precedente, se non si utilizza **other_options
viene **other_options
un ArgumentError: unknown keyword: foo, bar
verrebbe generato ArgumentError: unknown keyword: foo, bar
errore nella ArgumentError: unknown keyword: foo, bar
.
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
Questo è utile quando hai un hash di opzioni che vuoi passare ad un metodo e non vuoi filtrare le chiavi.
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!" }
È anche possibile decomprimere un hash utilizzando l'operatore **
. Ciò consente di fornire parole chiave direttamente a un metodo oltre ai valori di altri hash:
my_hash = { foo: 'Foo!', bar: 'Bar!' }
options(required_key: true, **my_hash)
#> { :foo => "Foo!", :bar => "Bar!" }
Cedendo ai blocchi
Puoi inviare un blocco al tuo metodo e può chiamare quel blocco più volte. Questo può essere fatto inviando un proc / lambda o tale, ma è più facile e veloce con 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
Nota che { puts ... }
non è all'interno delle parentesi, viene implicitamente dopo. Questo significa anche che possiamo avere solo un blocco di yield
. Possiamo passare argomenti alla 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
Con yield possiamo facilmente fare iteratori o funzioni che funzionano su altro codice:
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 effetti, è con il yield
che cose come foreach
, each
e le times
sono generalmente implementate nelle classi.
Se vuoi scoprire se ti è stato dato un blocco o no, usa 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 questo esempio si presuppone che la classe Employees
abbia un elenco @employees
che può essere iterato con each
per ottenere oggetti che hanno nomi di dipendenti che utilizzano il metodo name
. Se ci viene dato un blocco, poi ci yield
il nome al blocco, altrimenti basta spingerlo a una matrice che ci ritorno.
Tuple Arguments
Un metodo può prendere un parametro di matrice e destrutturarlo immediatamente in variabili locali con nome. Trovato sul blog di Mathias Meyer .
def feed( amount, (animal, food) )
p "#{amount} #{animal}s chew some #{food}"
end
feed 3, [ 'rabbit', 'grass' ] # => "3 rabbits chew some grass"
Definire un metodo
I metodi sono definiti con la parola chiave def
, seguita dal nome del metodo e da un elenco opzionale di nomi parametro tra parentesi. Il codice Ruby tra def
e end
rappresenta il corpo del metodo.
def hello(name)
"Hello, #{name}"
end
Un richiamo di metodo specifica il nome del metodo, l'oggetto su cui deve essere richiamato (talvolta chiamato il ricevente) e zero o più valori dell'argomento che sono assegnati ai parametri del metodo named.
hello("World")
# => "Hello, World"
Quando il ricevitore non è esplicito, è un self
.
I nomi dei parametri possono essere utilizzati come variabili all'interno del corpo del metodo e i valori di questi parametri denominati derivano dagli argomenti in una chiamata di metodo.
hello("World")
# => "Hello, World"
hello("All")
# => "Hello, All"
Utilizzare una funzione come blocco
Molte funzioni in Ruby accettano un blocco come argomento. Per esempio:
[0, 1, 2].map {|i| i + 1}
=> [1, 2, 3]
Se hai già una funzione che fa quello che vuoi, puoi trasformarlo in un blocco usando &method(:fn)
:
def inc(num)
num + 1
end
[0, 1, 2].map &method(:inc)
=> [1, 2, 3]