Add switch expression.

This commit is contained in:
Stephen Chung
2020-11-13 18:32:18 +08:00
parent 7d1b971b39
commit 55b4907f19
19 changed files with 547 additions and 252 deletions

View File

@@ -12,27 +12,19 @@ Use `type_of()` to Get Value Type
Because [`type_of()`] a `Dynamic` value returns the type of the actual value,
it is usually used to perform type-specific actions based on the actual value's type.
```rust
```c
let mystery = get_some_dynamic_value();
if type_of(mystery) == "i64" {
print("Hey, I got an integer here!");
} else if type_of(mystery) == "f64" {
print("Hey, I got a float here!");
} else if type_of(mystery) == "string" {
print("Hey, I got a string here!");
} else if type_of(mystery) == "bool" {
print("Hey, I got a boolean here!");
} else if type_of(mystery) == "array" {
print("Hey, I got an array here!");
} else if type_of(mystery) == "map" {
print("Hey, I got an object map here!");
} else if type_of(mystery) == "Fn" {
print("Hey, I got a function pointer here!");
} else if type_of(mystery) == "TestStruct" {
print("Hey, I got the TestStruct custom type here!");
} else {
print("I don't know what this is: " + type_of(mystery));
switch mystery {
"i64" => print("Hey, I got an integer here!"),
"f64" => print("Hey, I got a float here!"),
"string" => print("Hey, I got a string here!"),
"bool" => print("Hey, I got a boolean here!"),
"array" => print("Hey, I got an array here!"),
"map" => print("Hey, I got an object map here!"),
"Fn" => print("Hey, I got a function pointer here!"),
"TestStruct" => print("Hey, I got the TestStruct custom type here!"),
_ => print("I don't know what this is: " + type_of(mystery))
}
```

View File

@@ -0,0 +1,97 @@
`switch` Expression
===================
{{#include ../links.md}}
The `switch` _expression_ allows matching on literal values, and it mostly follows Rust's
`match` syntax:
```c
switch calc_secret_value(x) {
1 => print("It's one!"),
2 => {
print("It's two!");
print("Again!");
}
3 => print("Go!"),
// _ is the default when no cases match
_ => print("Oops! Something's wrong: " + x)
}
```
Expression, Not Statement
------------------------
`switch` is not a statement, but an expression. This means that a `switch` expression can
appear anywhere a regular expression can, e.g. as function call arguments.
```c
let x = switch foo { 1 => true, _ => false };
func(switch foo {
"hello" => 42,
"world" => 123,
_ => 0
});
// The above is somewhat equivalent to:
let x = if foo == 1 { true } else { false };
if foo == "hello" {
func(42);
} else if foo == "world" {
func(123);
} else {
func(0);
}
```
Array and Object Map Literals Also Work
--------------------------------------
The `switch` expression can match against any _literal_, including [array] and [object map] literals.
```c
// Match on arrays
switch [foo, bar, baz] {
["hello", 42, true] => { ... }
["hello", 123, false] => { ... }
["world", 1, true] => { ... }
_ => { ... }
}
// Match on object maps
switch map {
#{ a: 1, b: 2, c: true } => { ... }
#{ a: 42, d: "hello" } => { ... }
_ => { ... }
}
```
Difference From If-Else Chain
-----------------------------
Although a `switch` expression looks _almost_ the same as an `if`-`else` chain,
there are subtle differences between the two.
A `switch` expression matches through _hashing_ via a look-up table.
Therefore, matching is very fast. Walking down an `if`-`else` chain
will be _much_ slower.
On the other hand, operators can be [overloaded][operator overloading] in Rhai,
meaning that it is possible to override the `==` operator for integers such
that `if x == y` returns a different result from the built-in default.
`switch` expressions do _not_ use the `==` operator for comparison;
instead, they _hash_ the data values and jump directly to the correct
statements via a pre-compiled look-up table. This makes matching extremely
efficient, but it also means that [overloading][operator overloading]
the `==` operator will have no effect.
Therefore, in environments where it is desirable to [overload][operator overloading]
the `==` operator - though it is difficult to think of valid scenarios where you'd want
`1 == 1` to return something other than `true` - avoid using the `switch` expression.