Spec-Zone.ru › Crystal

case

case — это управляющее выражение, которое работает подобно сопоставлению с образцом. Оно позволяет записывать цепочки if-else-if с небольшим изменением семантики и использовать некоторые более мощные конструкции.

В базовой форме оно позволяет сопоставить значение с другими значениями:

case exp
when value1, value2
  do_something
when value3
  do_something_else
else
  do_another_thing
end

# The above is the same as:
tmp = exp
if value1 === tmp || value2 === tmp
  do_something
elsif value3 === tmp
  do_something_else
else
  do_another_thing
end

Для сравнения выражения со значением case используется оператор проверки равенства case ===. Он определён как метод в Object и может быть переопределён подклассами, чтобы обеспечить осмысленную семантику в инструкциях case. Например, Class определяет проверку равенства case так, что она возвращает истину, если объект является экземпляром этого класса; Regex — если значение соответствует регулярному выражению; а Range — если значение входит в этот диапазон.

Если выражение when имеет тип, используется is_a?. Кроме того, если выражение case является переменной или присваиванием переменной, тип переменной ограничивается:

case var
when String
  # var : String
  do_something
when Int32
  # var : Int32
  do_something_else
else
  # here var is neither a String nor an Int32
  do_another_thing
end

# The above is the same as:
if var.is_a?(String)
  do_something
elsif var.is_a?(Int32)
  do_something_else
else
  do_another_thing
end

Вызвать метод у выражения case в when можно с помощью синтаксиса неявного объекта:

case num
when .even?
  do_something
when .odd?
  do_something_else
end

# The above is the same as:
tmp = num
if tmp.even?
  do_something
elsif tmp.odd?
  do_something_else
end

После условия when можно использовать then, чтобы записать тело в одну строку.

case exp
when value1, value2 then do_something
when value3         then do_something_else
else                     do_another_thing
end

Наконец, можно опустить значение case:

case
when cond1, cond2
  do_something
when cond3
  do_something_else
end

# The above is the same as:
if cond1 || cond2
  do_something
elsif cond3
  do_something_else
end

Иногда так код выглядит естественнее при чтении.

Литерал кортежа

Если выражение case является литералом кортежа, возникают некоторые семантические отличия, когда условие when также является литералом кортежа.

Размеры кортежей должны совпадать

case {value1, value2}
when {0, 0} # OK, 2 elements
  # ...
when {1, 2, 3} # Syntax error: wrong number of tuple elements (given 3, expected 2)
  # ...
end

Подчёркивание допускается

case {value1, value2}
when {0, _}
  # Matches if 0 === value1, no test done against value2
when {_, 0}
  # Matches if 0 === value2, no test done against value1
end

Неявный объект допускается

case {value1, value2}
when {.even?, .odd?}
  # Matches if value1.even? && value2.odd?
end

Сравнение с типом выполняет проверку is_a?

case {value1, value2}
when {String, Int32}
  # Matches if value1.is_a?(String) && value2.is_a?(Int32)
  # The type of value1 is known to be a String by the compiler,
  # and the type of value2 is known to be an Int32
end

Исчерпывающий case

Использование in вместо when создаёт исчерпывающее выражение case; в исчерпывающем case пропуск любого из обязательных условий in приводит к ошибке компиляции. Исчерпывающий case не может содержать ни одного предложения when или else.

Компилятор поддерживает следующие условия in:

Проверки объединённого типа

Если выражение case имеет значение объединённого типа, в качестве условия можно использовать каждый из типов объединения:

# var : (Bool | Char | String)?
case var
in String
  # var : String
in Char
  # var : Char
in Bool
  # var : Bool
in nil # or Nil, but .nil? is not allowed
  # var : Nil
end

Логические значения

Если выражение case имеет значение типа Bool, в качестве условий можно использовать литералы true и false:

# var : Bool
case var
in true
  do_something
in false
  do_something_else
end

Значения перечисления

Если выражение case имеет значение перечисления без флагов, его элементы можно использовать в качестве условий — как константы или методы-предикаты.

enum Foo
  X
  Y
  Z
end

# var : Foo
case var
in Foo::X
  # var == Foo::X
in .y?
  # var == Foo::Y
in .z? # :z is not allowed
  # var == Foo::Z
end

Литералы кортежей

Условия должны охватывать все возможные сочетания элементов выражения case:

# value1, value2 : Bool
case {value1, value2}
in {true, _}
  # value1 is true, value2 can be true or false
  do_something
in {_, false}
  # here value1 is false, and value2 is also false
  do_something_else
end

# Error: case is not exhaustive.
#
# Missing cases:
#  - {false, true}

To the extent possible under law, the persons who contributed to this workhave waived
all copyright and related or neighboring rights to this workby associating CC0 with it.
https://crystal-lang.org/reference/1.2/syntax_and_semantics/case.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API