Ruby Language
Métodos
Buscar..
Introducción
Las funciones en Ruby proporcionan un código organizado y reutilizable para realizar un conjunto de acciones. Las funciones simplifican el proceso de codificación, evitan la lógica redundante y hacen que el código sea más fácil de seguir. Este tema describe la declaración y la utilización de funciones, argumentos, parámetros, declaraciones de rendimiento y alcance en Ruby.
Observaciones
Un método es un bloque de código con nombre, asociado con uno o más objetos y generalmente identificado por una lista de parámetros además del nombre.
def hello(name)
"Hello, #{name}"
end
La invocación de un método especifica el nombre del método, el objeto sobre el que se invoca (a veces se denomina receptor) y cero o más valores de argumento que se asignan a los parámetros del método nombrado. El valor de la última expresión evaluada en el método se convierte en el valor de la expresión de invocación del método.
hello("World")
# => "Hello, World"
Cuando el receptor no es explícito, es self
.
self
# => main
self.hello("World")
# => "Hello, World"
Como se explica en el libro de lenguaje de programación Ruby , muchos idiomas distinguen entre funciones, que no tienen un objeto asociado, y métodos, que se invocan en un objeto receptor. Debido a que Ruby es un lenguaje puramente orientado a objetos, todos los métodos son verdaderos métodos y están asociados con al menos un objeto.
Resumen de los parámetros del método
Tipo | Método Firma | Ejemplo de llamada | Asignaciones |
---|---|---|---|
R equipara | 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 palabra clave | def fn(a:0,b:1) | fn(a:2,b:3) | a=2, b=3 |
Estos tipos de argumentos pueden combinarse en prácticamente cualquier forma que pueda imaginar para crear funciones variables. El número mínimo de argumentos para la función será igual a la cantidad de argumentos requeridos en la firma. Los argumentos adicionales se asignarán a los parámetros predeterminados primero, luego al *rest
parámetros.
Tipo | Método Firma | Ejemplo de llamada | Asignaciones |
---|---|---|---|
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} |
Solo parámetro requerido
def say_hello_to(name)
puts "Hello #{name}"
end
say_hello_to('Charles') # Hello Charles
Múltiples parámetros requeridos
def greet(greeting, name)
puts "#{greeting} #{name}"
end
greet('Hi', 'Sophie') # Hi Sophie
Parámetros por defecto
def make_animal_sound(sound = 'Cuack')
puts sound
end
make_animal_sound('Mooo') # Mooo
make_animal_sound # Cuack
Es posible incluir valores predeterminados para múltiples argumentos:
def make_animal_sound(sound = 'Cuack', volume = 11)
play_sound(sound, volume)
end
make_animal_sound('Mooo') # Spinal Tap cow
Sin embargo, no es posible suministrar el segundo sin suministrar también el primero. En lugar de usar parámetros posicionales, pruebe los parámetros de palabras clave:
def make_animal_sound(sound: 'Cuack', volume: 11)
play_sound(sound, volume)
end
make_animal_sound(volume: 1) # Duck whisper
O un parámetro hash que almacena opciones:
def make_animal_sound(options = {})
options[:sound] ||= 'Cuak'
options[:volume] ||= 11
play_sound(sound, volume)
end
make_animal_sound(:sound => 'Mooo')
Los valores predeterminados de los parámetros pueden ser establecidos por cualquier expresión ruby. La expresión se ejecutará en el contexto del método, por lo que incluso puede declarar variables locales aquí. Tenga en cuenta, no obtendrá a través de la revisión de código. Cortesía de Caius por señalar esto .
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)
Parámetros opcionales (operador 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!
Tenga en cuenta que welcome_guests(['Rob', 'Sally', 'Lucas'])
emitirán Welcome ["Rob", "Sally", "Lucas"]!
En cambio, si tiene una lista, puede hacer welcome_guests(*['Rob', 'Sally', 'Lucas'])
y eso funcionará como welcome_guests('Rob', 'Sally', 'Lucas')
.
Mezcla opcional de parámetros por defecto requerida
def my_mix(name,valid=true, *opt)
puts name
puts valid
puts opt
end
Llame de la siguiente manera:
my_mix('me')
# 'me'
# true
# []
my_mix('me', false)
# 'me'
# false
# []
my_mix('me', true, 5, 7)
# 'me'
# true
# [5,7]
Las definiciones de los métodos son expresiones
La definición de un método en Ruby 2.x devuelve un símbolo que representa el nombre:
class Example
puts def hello
end
end
#=> :hello
Esto permite interesantes técnicas de metaprogramación. Por ejemplo, los métodos pueden ser envueltos por otros métodos:
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.
Capturando argumentos de palabras clave no declarados (doble splat)
El operador **
funciona de manera similar al operador *
, pero se aplica a los parámetros de palabras clave.
def options(required_key:, optional_key: nil, **other_options)
other_options
end
options(required_key: 'Done!', foo: 'Foo!', bar: 'Bar!')
#> { :foo => "Foo!", :bar => "Bar!" }
En el ejemplo anterior, si no se utilizan las **other_options
se **other_options
un ArgumentError: unknown keyword: foo, bar
error de 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
Esto es útil cuando tiene un hash de opciones que quiere pasar a un método y no quiere filtrar las claves.
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!" }
También es posible desempaquetar un hash usando el operador **
. Esto le permite suministrar palabras clave directamente a un método además de los valores de otros hashes:
my_hash = { foo: 'Foo!', bar: 'Bar!' }
options(required_key: true, **my_hash)
#> { :foo => "Foo!", :bar => "Bar!" }
Cediendo a bloques
Puede enviar un bloque a su método y puede llamar a ese bloque varias veces. Esto se puede hacer enviando un proc / lambda o similar, pero es más fácil y más rápido con el 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
Tenga en cuenta que { puts ... }
no está dentro de los paréntesis, implícitamente viene después. Esto también significa que solo podemos tener un bloque de yield
. Podemos pasar argumentos al 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 el rendimiento podemos hacer fácilmente iteradores o cualquier función que funcione en otro código:
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
De hecho, es con yield
que cosas como foreach
, each
y each
times
se implementan generalmente en las clases.
Si desea averiguar si le han dado un bloqueo o no, use 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
Este ejemplo asume que la clase Employees
tiene una lista de @employees
que se puede iterar con each
para obtener objetos que tienen nombres de empleados usando el método del name
. Si nos dan un bloque, entonces vamos a yield
el nombre al bloque, de lo contrario, simplemente empujar a una matriz que volvamos.
Argumentos de la tupla
Un método puede tomar un parámetro de matriz y destruirlo inmediatamente en variables locales nombradas. Encontrado en el blog de Mathias Meyer .
def feed( amount, (animal, food) )
p "#{amount} #{animal}s chew some #{food}"
end
feed 3, [ 'rabbit', 'grass' ] # => "3 rabbits chew some grass"
Definiendo un método
Los métodos se definen con la palabra clave def
, seguidos del nombre del método y una lista opcional de nombres de parámetros entre paréntesis. El código de Ruby entre def
y end
representa el cuerpo del método.
def hello(name)
"Hello, #{name}"
end
La invocación de un método especifica el nombre del método, el objeto sobre el que se invoca (a veces se denomina receptor) y cero o más valores de argumento que se asignan a los parámetros del método nombrado.
hello("World")
# => "Hello, World"
Cuando el receptor no es explícito, es self
.
Los nombres de los parámetros se pueden usar como variables dentro del cuerpo del método, y los valores de estos parámetros nombrados provienen de los argumentos a la invocación de un método.
hello("World")
# => "Hello, World"
hello("All")
# => "Hello, All"
Usa una función como bloque.
Muchas funciones en Ruby aceptan un bloque como argumento. P.ej:
[0, 1, 2].map {|i| i + 1}
=> [1, 2, 3]
Si ya tiene una función que hace lo que quiere, puede convertirla en un bloque usando &method(:fn)
:
def inc(num)
num + 1
end
[0, 1, 2].map &method(:inc)
=> [1, 2, 3]