Шрифт:
Интервал:
Закладка:
a = 10
p typeof(a) # => Int32
# Измените 'a', чтобы оно стало строкой String
a = "привет"
p typeof(a) # => String
# Возможно, 'a' изменится на Float64
if rand(1..2) == 1
a = 1.5
p typeof(a) # => Float64
end
# Теперь переменная 'a' может быть либо String либо Float64
p typeof(a) # => String | Float64
# Но мы можем узнать во время выполнения, какой это тип.
if a.is_a? String
puts "Это String"
p typeof(a) # => String
else
puts "Это Float64"
p typeof(a) # => Float64
end
# Тип 'a' был отфильтрован внутри условного выражения, но не изменился.
p typeof(a) # => String | Float64
# Вы также можете использовать .class для получения типа среды выполнения
puts "It's a #{a.class}"
В Crystal каждое значение является объектом, даже примитивные типы, такие как целые числа. Объекты имеют тип, и этот тип может реагировать на вызовы методов. Все операции, которые вы выполняете над объектом, проходят через вызов какого-либо метода. Даже nil является объектом типа Nil и может реагировать на методы. Например, nil.inspect возвращает "nil".
Все переменные имеют тип или, возможно, объединение нескольких типов. Когда это объединение, оно сохраняет объект одного из типов во время выполнения. Фактический тип можно определить с помощью оператора is_a? .
Методы, доступные данному типу, всегда известны компилятору. Таким образом, попытка вызвать несуществующий метод приведет к ошибке времени компиляции, а не к исключению времени выполнения.
К счастью, у Crystal есть инструмент, который помогает нам визуализировать типы по мере их вывода. Следующий раздел проведет вас через это.
Экспериментируем с командой Crystal Play
Команда crystal play запускает Crystal Playground для воспроизведения языка с помощью вашего браузера. Он покажет результат каждой строки вместе с выведенным типом:
1. Откройте терминал и введите "crystal play”; он покажет следующее сообщение:
Listening on http://127.0.0.1:8080
2. Оставьте терминал открытым, а затем запустите этот URL-адрес в своем любимом веб-браузере. Это даст вам удобный интерфейс для начала программирования в Crystal:
Рисунок 2.1 - The Crystal playground
1. С левой стороны у вас есть текстовый редактор с некоторым кодом Crystal. Вы можете попробовать изменить код на какой-нибудь код из этой книги, чтобы получить интерактивный способ обучения.
2. С правой стороны есть поле с некоторыми аннотациями к вашему коду. Например, он покажет вам результат каждой строки рядом с типом значения, видимым компилятором.
Если вы сомневаетесь в каких-то примерах или нестандартных решениях, попробуйте их с помощью Crystal playground.
Переходя к более практичному представлению о том, как используются типы, нам нужно узнать о хранении данных в коллекциях и манипулировании ими. Они всегда печатаются на машинке для обеспечения безопасности.
Организация вашего кода по методам
При написании приложений код необходимо структурировать таким образом, чтобы его можно было повторно использовать, документировать и тестировать. Основой этой структуры является создание методов. В следующей главе мы перейдем к объектно-ориентированному программированию с классами и модулями. Метод имеет имя, может получать параметры и всегда возвращает значение (nil также является значением). Посмотрите это, например:
def leap_year?(year) divides_by_4 = (year % 4 == 0)
divides_by_100 = (year % 100 == 0)
divides_by_400 = (year % 400 == 0)
divides_by_4 && !(divides_by_100 && !divides_by_400)
end
puts leap_year? 1900 # => false
puts leap_year? 2000 # => true
puts leap_year? 2020 # => true
Определения методов начинаются с ключевого слова def, за которым следует имя метода. В данном случае имя метода — jump_year?, включая символ вопроса. Затем, если у метода есть параметры, они будут заключены в круглые скобки. Метод всегда возвращает результат своей последней строки, в данном примере — условный результат. Типы не нужно указывать явно, они будут определяться в зависимости от использования.
При вызове метода круглые скобки вокруг аргументов не являются обязательными и часто опускаются для удобства чтения. В этом примере puts — это метод, аналогичный jump_year? и его аргумент является результатом последнего. ставит leap_year? 1900 — это то же самое, что и puts(leap_year?(1900)).
Имена методов подобны переменным и соответствуют соглашению об использовании только строчных букв, цифр и подчеркиваний. Кроме того, имена методов могут заканчиваться символами вопроса или восклицательного знака. Они не имеют специального значения в языке, но обычно применяются в соответствии со следующим соглашением:
• Метод, заканчивающийся на ? может указывать на то, что метод проверяет какое-то условие и возвращает значение Bool. Он также часто используется для методов, которые возвращают объединение некоторого типа и Nil для обозначения состояния сбоя.
• Метод, заканчивающийся на ! указывает на то, что выполняемая им операция в некотором роде «опасна», и программисту следует быть осторожным при ее использовании. Иногда может существовать «более безопасный» вариант метода с тем же именем, но без ! символ.
Методы могут основываться на других методах. Посмотрите это, например:
def day_count(year)
leap_year?(year) ? 366 : 365
end
Методы могут быть перегружены по количеству аргументов. Посмотрите это, например:
def day_count(year, month)
case month
when 1, 3, 5, 7, 8, 10, 12
31
when 2
leap_year?(year) ? 29 : 28
else
30
end
end
В этом случае метод будет выбран в зависимости от того, как вы расставите аргументы для его вызова:
puts day_count(2020) # => 366
puts day_count(2021) # => 365
puts day_count(2020, 2) # => 29
Внутри методов ключевое слово return можно использовать для досрочного завершения выполнения метода, при необходимости доставляя значение вызывающему методу. Последнее выражение в теле метода ведет себя как неявный возврат. Чаще всего он используется внутри