Выбрать главу

def store_opening_time(is_weekend, is_holiday)

   if is_holiday

       is weekend ? nil : "8:00"

   else

       is_weekend ? "12:00" : "9:00"

   end

end

В этой реализации нет ничего необычного. Но если вы начнете его использовать, все быстро станет очень запутанным:

p store_opening_time(true, false) # What is 'true' and 'false' here?

You can call the same method while specifying the name of each parameter for clarity:

p store_opening_time(is_weekend: true, is_holiday: false)

Чтобы принудительно дать имена некоторым параметрам, добавьте перед ними символ *. Все, что слева от *, будет позиционными параметрами, а все, что справа, всегда будет именованными параметрами. Они также могут иметь значения по умолчанию:

def store_opening_time(*, is_weekend, is_holiday)

    # ...

end

p store_opening_time(is_weekend: true, is_holiday: false)

p store_opening_time(is_weekend: true, is_holiday: false)

p store_opening_time(true, false) # Invalid!

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

Внешние и внутренние имена параметров

Иногда параметр может иметь имя, которое имеет большой смысл в качестве описания аргумента для вызывающего объекта, но может звучать странно при использовании в качестве переменной в теле реализации метода. Crystal позволяет вам определить внешнее имя (видимое для вызывающего объекта) и внутреннее имя (видимое для реализации метода). По умолчанию они одинаковы, но это не обязательно. Посмотрите это, например:

def multiply(value, *, by factor, adding term = 0)

   value * factor + term

end

p multiply(3, by: 5) # => 15

p multiply(2, by: 3, adding: 10) # => 16

Этот метод принимает два или три параметра. Первый называется значением и является позиционным параметром, то есть его можно вызывать без указания имени. Следующие два параметра названы из-за символа *. Второй параметр имеет внешнее имя by и внутреннее имя фактора. Третий и последний параметр имеет добавление внешнего имени и термин внутреннего имени. Он также имеет значение по умолчанию 0, поэтому это необязательно. Эту функцию можно использовать для того, чтобы сделать вызов методов с именованными параметрами более естественным.

Передача блоков в методы

Методы являются основой для организации и повторного использования кода. Но для дальнейшего улучшения этого метода методы повторного использования также могут получать блоки кода при вызове. Внутри метода вы можете использовать ключевое слово yield для вызова полученного блока столько раз, сколько необходимо.

Определить метод, который получает блок, просто; просто используйте выход внутри него. Посмотрите это, например:

def perform_operation

    puts "before yield"

    yield

    puts "between yields"

    yield

    puts "after both yields"

end

Затем этот метод можно вызвать, передав блок кода либо вокруг do ... end, либо в фигурных скобках { ... }:

perform_operation {

    puts "inside block"

}

perform_operation do

    puts "inside block"

end

Выполнение этого кода приведет к следующему выводу:

before yield

inside block

between yields

inside block

after both yields

Вы можете видеть, что сообщение внутреннего блока происходит между операторами тела метода. Он появляется дважды, поскольку код внутри блока выполнялся при каждом выходе основного метода.

Но для хорошей работы кода внутри блока может потребоваться некоторый контекст. По этой причине блоки также могут получать аргументы и возвращаемые значения. Вот пример метода, который преобразует элементы массива во что-то другое:

def transform(list)

   i = 0

   # new_list is an Array made of whatever type the block returns

   new_list = [] of typeof(yield list[0])

   while i < list.size

       new_list << yield list[i]

       i += 1

   end

   new_list

end

numbers = [1, 2, 3, 4, 5]

p transform(numbers) { |n| n ** 2 } # => [1, 4, 9, 16, 25] p transform(numbers) { |n| n.to_s } # => ["1", "2", "3", "4", "5"]

Ключевое слово доходность ведет себя как вызов метода: вы можете передать ему аргументы, и оно вернет результат вызова блока. Параметры блока указываются между парой символов вертикальной черты (|), разделенных запятыми, если их несколько.

Вышеупомянутый метод преобразования эквивалентен методу карты, доступному для массивов: