puts "Извините, это не то. Пожалуйста, попробуйте еще раз: "
guess = read_line.to_i
end
puts "Вы правильно угадали!"
Внутри циклической структуры вы можете использовать следующие дополнительные ключевые слова:
• break
— немедленно прерывает цикл и выходит из него без повторной проверки условия.
• next
— прерывает текущее выполнение цикла и начинает заново с начала, проверяя условие
Вот пример использования break
и next
для дальнейшего управления потоком:
secret_number = rand(1..5)
while true
print "Пожалуйста, введите свое предположение (ноль, чтобы отказаться): "
guess = read_line.to_i
if guess < 0 || guess > 5
puts "Неверное предположение. Пожалуйста, попробуйте еще раз."
next
end
if guess == 0
puts "Извините, вы сдались. Ответ был #{secret_number}."
break
elsif guess == secret_number
puts "Поздравляем! Вы угадали секретный номер!"
break
end
puts "Извините, это не то. Пожалуйста, попробуйте еще раз."
end
Они составляют основу управления потоком выполнения с использованием условий и структуры цикла. Далее в этой главе вы также узнаете о блоках — наиболее распространенном способе создания циклов в Crystal, особенно с контейнерами данных. Но перед этим давайте углубимся в систему типов.
Изучение системы типов
Crystal — статически типизированный язык; компилятор знает типы каждой переменной и выражения перед выполнением. Это позволяет выполнить несколько проверок правильности вашего кода, например проверить существование вызванных методов и соответствие переданных аргументов сигнатуре или убедиться, что вы не пытаетесь получить доступ к нулевым свойствам.
Одного типа недостаточно в каждой ситуации: одну переменную можно переназначить значениям разных типов, и, таким образом, тип переменной может быть любым из типов каждого значения. Это можно выразить с помощью типа объединения, типа, созданного путем объединения всех возможных типов. Благодаря этому компилятор знает, что переменная может содержать значение любого из этих типов во время выполнения.
Вы можете использовать оператор typeof(x)
, чтобы определить тип любого выражения или переменной, видимый компилятором. Это может быть объединение нескольких типов. Вы также можете использовать x.class
для определения типа значения во время выполнения; это никогда не будет союзом. Наконец, существует оператор x.is_a?(Type)
, позволяющий проверить, принадлежит ли что-либо заданному типу, что полезно для разветвления и выполнения действий по-разному. Ниже приведены некоторые примеры:
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?
.