Шрифт:
Интервал:
Закладка:
# 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 вызывает полученный блок три раза, а затем
- QT 4: программирование GUI на С++ - Жасмин Бланшет - Программирование
- C# для профессионалов. Том II - Симон Робинсон - Программирование
- Как спроектировать современный сайт - Чои Вин - Программирование
- Microsoft Visual C++ и MFC. Программирование для Windows 95 и Windows NT. Часть 2 - Александр Фролов - Программирование
- Краткое введение в программирование на Bash - Гарольд Родригес - Программирование
- Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен - Программирование
- Каждому проекту своя методология - Алистэр Коуберн - Программирование
- Разработка ядра Linux - Роберт Лав - Программирование
- Графические интерфейсы пользователя Java - Тимур Сергеевич Машнин - Программирование
- C# 4.0: полное руководство - Герберт Шилдт - Программирование