case
case
A case
is a control expression which functions a bit like pattern matching. It allows writing a chain of if-else-if with a small change in semantic and some more powerful constructs.
In its basic form, it allows matching a value against other values:
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
Note that ===
is used for comparing an expression against a case
's value.
If a when
's expression is a type, is_a?
is used. Additionally, if the case expression is a variable or a variable assignment the type of the variable is restricted:
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
You can invoke a method on the case
's expression in a when
by using the implicit-object syntax:
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
Finally, you can omit the case
's value:
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
This sometimes leads to code that is more natural to read.
Tuple literal
When a case expression is a tuple literal there are a few semantic differences if a when condition is also a tuple literal.
Tuple size must match
case {value1, value2} when {0, 0} # OK, 2 elements # ... when {1, 2, 3} # Compiler error, because it will never match # ... end
Underscore allowed
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
Implicit-object allowed
case {value1, value2} when {.even?, .odd?} # Matches if value1.even? && value2.odd? end
Comparing against a type will perform an is_a? check
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
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/docs/syntax_and_semantics/case.html