# (3) Same result, short block syntax
p fruits.map &.upcase
В первом фрагменте (1) использовался метод карты вместе с блоком do... end. Метод map выполняет итерацию по массиву, передавая блок для каждого элемента и создавая новый массив с результатом блока. В этом первом примере необходимы круглые скобки, поскольку do...end блоки подключаются к самому внешнему методу, в данном случае p.
Второй фрагмент (2) использует синтаксис { ... } и может опускать круглые скобки, поскольку этот блок подключается к ближайшему вызову метода. Обычно синтаксис { ... } записывается в одну строку, но это не обязательно.
Наконец, мы видим синтаксис коротких блоков в третьем фрагменте (3). Написание &.foo аналогично использованию { |x| x.foo }. Его также можно записать как p fruits.map(&.upcase), как если бы блок был общим аргументом вызова метода.
Отличается только синтаксис; поведение и семантика всех трех фрагментов одинаковы. Обычно везде, где это возможно, используется синтаксис коротких блоков.
Контейнер Tuple также отображается в определениях методов при использовании параметров splat.
Параметры сплата (Splat)
Метод можно определить так, чтобы он принимал произвольное количество аргументов, используя параметры splat. Это делается путем добавления символа * перед именем параметра: теперь при вызове метода он будет ссылаться на кортеж с нулевым или более значениями аргументов. Посмотрите это, например:
def get_pop(population, *countries)
puts "Requested countries: #{countries}"
countries.map { |country| population[country] }
end
puts get_pop(population, "Indonesia", "China", "United States")
Этот код даст следующий результат:
Requested countries: {"Indonesia", "China", "United States"}
{273523615, 1439323776, 331002651}
Использование splat всегда будет создавать кортежи правильных типов, как если бы метод имел такое количество обычных позиционных параметров. В этом примере typeof(countries) будет Tuple(String, String, String); тип будет меняться при каждом использовании. Параметры Splat — наиболее распространенный вариант использования кортежей.
Организация вашего кода в файлах
Написание кода в одном файле подходит для некоторых быстрых тестов или очень небольших приложений, но все остальное в конечном итоге придется организовывать в нескольких файлах. Всегда существует основной файл, который вы передаете команде crystal run или crystal build, но этот файл может ссылаться на код в других файлах с ключевым словом require. Компиляция всегда начинается с анализа этого основного файла, а затем рекурсивного анализа любого файла, на который он ссылается, и так далее.
Разберем пример:
1. Сначала создайте файл с именем Factorial.cr:
def factorial(n)
(1..n).product
end
2. Затем создайте файл с именем program.cr:
require "./factorial"
(1..10).each do |i|
puts "#{i}! = #{factorial(i)}"
end
В этом примере require «./factorial» будет искать файл с именем factorial.cr в той же папке, что и program.cr, и импортируйте все, что он определяет. Невозможно выбрать только часть того, что определяют необходимые файлы; требуют импорта всего последовательно. Запустите этот пример с помощью crystal run program.cr.
Один и тот же файл не может быть импортирован дважды; компилятор Crystal проверит и проигнорирует такие попытки.
Вам могут потребоваться файлы двух типов: это либо файл из вашего проекта — в этом случае для ссылки на него используется относительный путь, начинающийся с расширения . - или это файл библиотеки, взятый из стандартной библиотеки или из установленной вами зависимости. В этом случае имя используется напрямую, без относительного пути.
require "./filename"
Начальный параметр ./ сообщает Crystal искать этот файл в текущем каталоге относительно текущего файла. Он будет искать файл с именем filename.cr или каталог с именем filename, в котором находится файл с именем filename.cr. Вы также можете использовать ../ для ссылки на родительский каталог.
Также поддерживаются шаблоны Glob для импорта всех файлов из заданного каталога, как здесь:
require "./commands/*"
Это импортирует все файлы Crystal в каталог команд. Импорт всего из текущего каталога также допустим:
require
Эта нотация используется в первую очередь для ссылки на файлы из вашего собственного проекта. При ссылке на файлы из установленной библиотеки или стандартной библиотеки Crystal путь не начинается с расширения ..