Поиск…


Вступление

Функции в Ruby предоставляют организованный, многоразовый код для предварительной последовательности действий. Функции упрощают процесс кодирования, предотвращают избыточную логику и упрощают выполнение кода. В этом разделе описывается декларация и использование функций, аргументов, параметров, операторов вывода и области действия в Ruby.

замечания

Метод - это именованный блок кода, связанный с одним или несколькими объектами и обычно идентифицируемый списком параметров в дополнение к имени.

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

Вызов метода указывает имя метода, объект, на который он должен быть вызван (иногда называемый получателем), и ноль или более значений аргумента, назначенных параметрам именованного метода. Значение последнего выражения, оцененного в методе, становится значением выражения вызова метода.

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

Когда приемник не является явным, он self .

self
# => main

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

Как объясняется в книге языка программирования Ruby , многие языки различают функции, которые не имеют связанного с ними объекта, и методы, которые вызывают на объекте получателя. Поскольку Ruby является чисто объектно-ориентированным языком, все методы являются истинными методами и связаны с хотя бы одним объектом.

Обзор параметров метода

Тип Подпись метода Пример вызова Назначения
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

Эти типы аргументов можно комбинировать практически так, как вы можете себе представить, для создания вариативных функций. Минимальное количество аргументов функции будет равно количеству необходимых аргументов в сигнатуре. Дополнительные аргументы сначала будут назначены параметрам по умолчанию, а затем - параметру *rest .

Тип Подпись метода Пример вызова Назначения
R, D, В, Р 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
В.К. 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}

Единый требуемый параметр

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

say_hello_to('Charles')    # Hello Charles

Несколько требуемых параметров

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

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

Параметры по умолчанию

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

make_animal_sound('Mooo') # Mooo
make_animal_sound         # Cuack

Можно включить значения по умолчанию для нескольких аргументов:

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

make_animal_sound('Mooo') # Spinal Tap cow

Тем не менее, невозможно поставить второй, не поставляя первый. Вместо использования позиционных параметров попробуйте параметры ключевых слов:

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

make_animal_sound(volume: 1) # Duck whisper

Или хеш-параметр, в котором хранятся параметры:

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

make_animal_sound(:sound => 'Mooo') 

Значения параметров по умолчанию могут быть заданы любым выражением ruby. Выражение будет выполняться в контексте метода, поэтому вы можете даже объявить локальные переменные здесь. Обратите внимание, что вы не сможете пройти проверку кода. Предоставлено caius для указания этого .

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)

Необязательный параметр (ы) (оператор 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!

Обратите внимание, что welcome_guests(['Rob', 'Sally', 'Lucas']) выводит Welcome ["Rob", "Sally", "Lucas"]!
Вместо этого, если у вас есть список, вы можете делать welcome_guests(*['Rob', 'Sally', 'Lucas']) и это будет работать как welcome_guests('Rob', 'Sally', 'Lucas') .

Требуемый необязательный параметр параметров

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

Вызовите следующее:

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

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

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

Определения метода - это выражения

Определение метода в Ruby 2.x возвращает символ, обозначающий имя:

class Example
  puts def hello
  end
end

#=> :hello

Это позволяет использовать интересные методы метапрограммирования. Например, методы могут быть обернуты другими способами:

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.

Захват необъявленных аргументов ключевого слова (двойной знак)

Оператор ** работает аналогично оператору * но применяется к параметрам ключевых слов.

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

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

В приведенном выше примере, если **other_options не используется, будет **other_options сообщение 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

Это удобно, если у вас есть хэш опций, которые вы хотите передать методу, и вы не хотите фильтровать ключи.

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

Также можно распаковать хэш с помощью оператора ** . Это позволяет вам добавлять ключевое слово непосредственно к методу в дополнение к значениям из других хэшей:

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

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

Уступка блокам

Вы можете отправить блок в свой метод, и он может вызывать этот блок несколько раз. Это может быть сделано путем отправки ргос / лямбда или , например, но проще и быстрее с 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

Обратите внимание, что { puts ... } не находится внутри круглых скобок, он неявно приходит после. Это также означает, что мы можем иметь только один блок yield . Мы можем передать аргументы в 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

С выходом мы можем легко сделать итераторы или любые функции, которые работают с другим кодом:

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

Фактически, с yield такие вещи, как foreach , each и times , обычно реализуются в классах.

Если вы хотите узнать, был ли вам предоставлен блок или нет, используйте 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

В этом примере предполагается, что класс Employees имеет список @employees который можно @employees с each чтобы получить объекты, у которых есть имена сотрудников, используя метод name . Если задана блок, то мы будем yield имя к блоку, в противном случае мы просто вставьте его в массив , что мы вернемся.

Корректные аргументы

Метод может принимать параметр массива и немедленно разрушать его в именованных локальных переменных. Найдено в блоге Матиаса Мейера .

def feed( amount, (animal, food) )

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

end

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

Определение метода

Методы определяются с ключевым словом def , за которым следует имя метода и необязательный список имен параметров в круглых скобках. Код Ruby между def и end представляет собой тело метода.

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

Вызов метода указывает имя метода, объект, на который он должен быть вызван (иногда называемый получателем), и ноль или более значений аргумента, назначенных параметрам именованного метода.

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

Когда приемник не является явным, он self .

Имена параметров могут использоваться как переменные внутри тела метода, а значения этих именованных параметров поступают от аргументов к вызову метода.

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

Использовать функцию как блок

Многие функции в Ruby принимают блок как аргумент. Например:

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

Если у вас уже есть функция, которая делает то, что вы хотите, вы можете превратить ее в блок using &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
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow