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