Ruby Language
Metody
Szukaj…
Wprowadzenie
Funkcje w Rubim zapewniają zorganizowany kod wielokrotnego użytku, aby wykonać zestaw działań. Funkcje upraszczają proces kodowania, zapobiegają nadmiarowej logice i ułatwiają śledzenie kodu. W tym temacie opisano deklarację i wykorzystanie funkcji, argumentów, parametrów, instrukcji return i zakresu w Ruby.
Uwagi
Metoda to nazwany blok kodu, powiązany z jednym lub większą liczbą obiektów i ogólnie identyfikowany przez listę parametrów oprócz nazwy.
def hello(name)
"Hello, #{name}"
end
Wywołanie metody określa nazwę metody, obiekt, na który ma zostać wywołany (czasami nazywany odbiornikiem), oraz zero lub więcej wartości argumentów przypisanych do nazwanych parametrów metody. Wartość ostatniego wyrażenia ocenianego w metodzie staje się wartością wyrażenia wywołania metody.
hello("World")
# => "Hello, World"
Kiedy odbiorca nie jest jawny, jest self
.
self
# => main
self.hello("World")
# => "Hello, World"
Jak wyjaśniono w książce Ruby Programming Language , wiele języków rozróżnia funkcje, które nie mają powiązanego obiektu, oraz metody, które są wywoływane na obiekcie odbiorcy. Ponieważ Ruby jest językiem czysto obiektowym, wszystkie metody są prawdziwymi metodami i są powiązane z co najmniej jednym obiektem.
Przegląd parametrów metody
Rodzaj | Podpis metody | Przykład połączenia | Przydziały |
---|---|---|---|
R equired | 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 |
Te typy argumentów można łączyć praktycznie w dowolny sposób, jaki można sobie wyobrazić w celu tworzenia funkcji variadic. Minimalna liczba argumentów funkcji będzie równa liczbie wymaganych argumentów w podpisie. Dodatkowe argumenty zostaną przypisane najpierw do parametrów domyślnych, a następnie do parametru *rest
.
Rodzaj | Podpis metody | Przykład połączenia | Przydziały |
---|---|---|---|
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} |
Jeden wymagany parametr
def say_hello_to(name)
puts "Hello #{name}"
end
say_hello_to('Charles') # Hello Charles
Wiele wymaganych parametrów
def greet(greeting, name)
puts "#{greeting} #{name}"
end
greet('Hi', 'Sophie') # Hi Sophie
Parametry domyślne
def make_animal_sound(sound = 'Cuack')
puts sound
end
make_animal_sound('Mooo') # Mooo
make_animal_sound # Cuack
Możliwe jest dołączenie wartości domyślnych dla wielu argumentów:
def make_animal_sound(sound = 'Cuack', volume = 11)
play_sound(sound, volume)
end
make_animal_sound('Mooo') # Spinal Tap cow
Jednak nie jest możliwe dostarczenie drugiego bez dostarczenia pierwszego. Zamiast używać parametrów pozycyjnych, wypróbuj parametry słów kluczowych:
def make_animal_sound(sound: 'Cuack', volume: 11)
play_sound(sound, volume)
end
make_animal_sound(volume: 1) # Duck whisper
Lub parametr skrótu przechowujący opcje:
def make_animal_sound(options = {})
options[:sound] ||= 'Cuak'
options[:volume] ||= 11
play_sound(sound, volume)
end
make_animal_sound(:sound => 'Mooo')
Domyślne wartości parametrów można ustawić za pomocą dowolnego wyrażenia ruby. Wyrażenie będzie działać w kontekście metody, więc możesz nawet zadeklarować tutaj zmienne lokalne. Uwaga: nie przejdzie przeglądu kodu. Dzięki uprzejmości kaiusa za zwrócenie na to uwagi .
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)
Opcjonalne parametry (operator ikony)
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!
Zauważ, że welcome_guests(['Rob', 'Sally', 'Lucas'])
wyświetli Welcome ["Rob", "Sally", "Lucas"]!
Zamiast tego, jeśli masz listę, możesz zrobić welcome_guests(*['Rob', 'Sally', 'Lucas'])
a to zadziała jako welcome_guests('Rob', 'Sally', 'Lucas')
.
Wymagany domyślny opcjonalny miks parametrów
def my_mix(name,valid=true, *opt)
puts name
puts valid
puts opt
end
Zadzwoń w następujący sposób:
my_mix('me')
# 'me'
# true
# []
my_mix('me', false)
# 'me'
# false
# []
my_mix('me', true, 5, 7)
# 'me'
# true
# [5,7]
Definicje metod są wyrażeniami
Definiowanie metody w Ruby 2.x zwraca symbol reprezentujący nazwę:
class Example
puts def hello
end
end
#=> :hello
Pozwala to na ciekawe techniki metaprogramowania. Na przykład metody można łączyć innymi metodami:
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.
Przechwytywanie niezadeklarowanych argumentów słów kluczowych (podwójna ikona)
Operator **
działa podobnie do operatora *
, ale dotyczy parametrów słów kluczowych.
def options(required_key:, optional_key: nil, **other_options)
other_options
end
options(required_key: 'Done!', foo: 'Foo!', bar: 'Bar!')
#> { :foo => "Foo!", :bar => "Bar!" }
W powyższym przykładzie, jeśli nie zostanie użyta **other_options
ArgumentError: unknown keyword: foo, bar
zostanie podniesione ArgumentError: unknown keyword: foo, bar
błąd 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
Jest to przydatne, gdy masz skrót opcji, które chcesz przekazać do metody i nie chcesz filtrować kluczy.
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!" }
Możliwe jest również rozpakowanie skrótu za pomocą operatora **
. Pozwala to na dostarczenie słowa kluczowego bezpośrednio do metody oprócz wartości z innych skrótów:
my_hash = { foo: 'Foo!', bar: 'Bar!' }
options(required_key: true, **my_hash)
#> { :foo => "Foo!", :bar => "Bar!" }
Uleganie blokom
Możesz wysłać blok do metody, która może wywołać ten blok wiele razy. Można to zrobić wysyłając proc / lambda lub podobny, ale jest to łatwiejsze i szybsze z 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
Zauważ, że { puts ... }
nie znajduje się w nawiasach, domyślnie następuje. Oznacza to również, że możemy mieć tylko jeden blok yield
. Możemy przekazać argumenty do 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
Z wydajnością możemy łatwo tworzyć iteratory lub dowolne funkcje działające na innym kodzie:
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
W rzeczywistości z yield
rzeczy takie jak foreach
each
times
generowane w klasach.
Jeśli chcesz się dowiedzieć, czy dostałeś blok, czy nie, użyj 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
W tym przykładzie założono, że klasa Employees
ma listę @employees
którą można iterować z each
z each
aby uzyskać obiekty o nazwach pracowników przy użyciu metody name
. Jeśli podano blok, a następnie będziemy yield
nazwę do bloku, w przeciwnym razie po prostu wcisnąć go do tablicy, że wracamy.
Argumenty krotkie
Metoda może pobrać parametr tablicy i natychmiast go zniszczyć na nazwane zmienne lokalne. Znaleziono na blogu Mathiasa Meyera .
def feed( amount, (animal, food) )
p "#{amount} #{animal}s chew some #{food}"
end
feed 3, [ 'rabbit', 'grass' ] # => "3 rabbits chew some grass"
Definiowanie metody
Metody są definiowane za pomocą słowa kluczowego def
, po którym następuje nazwa metody i opcjonalna lista nazw parametrów w nawiasach. Kod Ruby między def
a end
reprezentuje treść metody.
def hello(name)
"Hello, #{name}"
end
Wywołanie metody określa nazwę metody, obiekt, na który ma zostać wywołany (czasami nazywany odbiornikiem), oraz zero lub więcej wartości argumentów przypisanych do nazwanych parametrów metody.
hello("World")
# => "Hello, World"
Kiedy odbiorca nie jest jawny, jest self
.
Nazwy parametrów mogą być używane jako zmienne w treści metody, a wartości tych nazwanych parametrów pochodzą od argumentów do wywołania metody.
hello("World")
# => "Hello, World"
hello("All")
# => "Hello, All"
Użyj funkcji jako bloku
Wiele funkcji w Ruby akceptuje blok jako argument. Na przykład:
[0, 1, 2].map {|i| i + 1}
=> [1, 2, 3]
Jeśli masz już funkcję, która robi to, co chcesz, możesz przekształcić ją w blok za pomocą &method(:fn)
:
def inc(num)
num + 1
end
[0, 1, 2].map &method(:inc)
=> [1, 2, 3]