litbaza книги онлайнРазная литератураCrystal Programming. Введение на основе проекта в создание эффективных, безопасных и читаемых веб-приложений и приложений CLI - Джордж Дитрих

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 8 9 10 11 12 13 14 15 16 ... 75
Перейти на страницу:
означает каждый из них. Чтобы улучшить это, параметры могут быть названы в месте вызова. Вот пример:

# These are all the same:

p random_score(5, 5)

p random_score(5, max: 5)

p random_score(base: 5, max: 5)

p random_score(max: 5, base: 5)

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

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

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"]

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

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

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

p numbers.map { |n| n ** 2 } # => [1, 4, 9, 16, 25]

p numbers.map { |n| n.to_s } # => ["1", "2", "3", "4", "5"]

В Crystal уже определено множество других методов, использующих блоки; наиболее распространенными являются те, которые используются для перебора элементов коллекции данных.

Как и while и until, ключевые слова next и break также можно использовать внутри блоков.

Использование next внутри блока

Используйте next, чтобы остановить текущее выполнение блока и вернуться к оператору yield, который его вызвал. Если значение передается в next, yield получит выход. Посмотрите это, например:

def generate

  first = yield 1   # This will be 2

  second = yield 2  # This will be 10

  third = yield 3   # This will be 4

  first + second + third

end

result = generate do |x|

  if x == 2

     next 10

  end

  x + 1

end

p result

Метод generate вызывает полученный блок три раза, а затем

1 ... 8 9 10 11 12 13 14 15 16 ... 75
Перейти на страницу:

Комментарии
Минимальная длина комментария - 20 знаков. Уважайте себя и других!
Комментариев еще нет. Хотите быть первым?