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

# (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 путь не начинается с расширения ..