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

  puts "Мы в третьем квартале"

when 10..12

  puts "Мы в четвертом квартале"

end

Его также можно использовать с типами данных вместо значений или диапазонов:

int_or_string = rand(1..2) == 1 ? 10 : "привет"

case int_or_string

when Int32

  puts "Это целое число"

when String

  puts "Это строка"

end

Таким образом, интересно использовать оператор case для проверки других вещей, кроме прямого равенства. Это работает, потому что за кулисами case использует оператор === для сравнения целевого значения с каждым предложением if. Вместо строгого равенства оператор === проверяет равенство или совместимость с заданным набором и является более расслабленным.

Как и оператор if, оператор case также может иметь ветвь else, если ни один из параметров не соответствует:

case rand(1..10)

when 1..3

  puts "Я кот"

when 4..6

  puts "Я собака"

else

  puts "Я случайное животное"

end

На данный момент вы научились использовать переменные, вызывать методы и выполнять различные операции с условными выражениями. Но также очень полезно повторять выполнение до тех пор, пока какое-либо условие не станет истинным, например, при поиске данных или преобразовании элементов. Теперь вы узнаете о примитивах, позволяющих сделать именно это.

while и until loops

Оператор while аналогичен оператору if, но он повторяется до тех пор, пока условие не станет ложным. Посмотрите это, например:

secret_number = rand(1..5)

print "Пожалуйста, введите ваше предположение: "

guess = read_line.to_i

while guess != secret_number

  puts "Извините, это не то. Пожалуйста, попробуйте еще раз: "

  guess = read_line.to_i

end

puts "Вы правильно угадали!"

Аналогично, оператор until является противоположностью оператора while, так же, как оператор unless является противоположностью оператора if:

secret_number = rand(1..5)

print "Пожалуйста, введите ваше предположение: "

guess = read_line.to_i

until guess == secret_number

  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), позволяющий проверить, принадлежит ли что-либо заданному типу, что полезно для разветвления и выполнения действий по-разному. Ниже приведены некоторые примеры: