> For the complete documentation index, see [llms.txt](https://osh.fducslg.com/notes/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://osh.fducslg.com/notes/rust/expressions.md).

# Expressions

In C, expressions and statements are different. Expressions have values. Statements don’t.

In Rust, `if` and `match` *can* produce values. Most of the control flow tools in C are statements. In Rust, they are all expressions.

## Declarations

You may occasionally see code that seems to redeclare an existing variable, like this:

```rust
for line in file.lines() {
    let line = line?;
    ...
}

// equivalent to

for line_result in file.lines() {
    let line = line_result?;
    ...
}
```

The `let` declaration creates a new, second variable, of a different type. The type of the first variable `line` is `Result<String, io::Error>`. The second `line` is a `String`. Its definition supersedes the first’s for the rest of the block. This is called ***shadowing*** and is very common in Rust programs.

When an `fn` is declared inside a block, its scope is the entire block—that is, it can be *used* throughout the enclosing block. A nested `fn` **cannot access local variables or arguments** that happen to be in scope.

## `if` and `match`

```rust
match code {
    0 => println!("OK"),
    1 => println!("Wires Tangled"),
    2 => println!("User Asleep"),
    _ => println!("Unrecognized Error {}", code)
}
```

All blocks of an `if` expression must produce values of the same type. Similarly, all arms of a `match` expression must have the same type.

### `if let`

```rust
if let pattern = expr {
    block1
} else {
    block2
}
```

The given `expr` either matches the `pattern`, in which case `block1` runs, or doesn’t match, and `block2` runs.

## Loops

```rust
while condition {
  block
}

while let pattern = expr {
  block
}

loop {
  // Use loop to write infinite loops. It executes the block repeatedly forever (or until a break or return is reached or the thread panics).
  block
}

for pattern in iterable {
  block
}
```

The `..` operator produces a *range*, a simple struct with two fields: `start` and `end`. `0..20` is the same as `std::ops::Range { start: 0, end: 20 }`. Ranges can be used with `for` loops because `Range` is an iterable type: it implements the `std::iter::IntoIterator` trait.

```rust
let strings: Vec<String> = error_messages();
for s in strings {                  // each String is moved into s here...
    println!("{}", s);
}                                   // ...and dropped here
println!("{} error(s)", strings.len()); // error: use of moved value
```

### Control Flow in Loops

Within the body of a `loop`, you can give `break` an expression, whose value becomes that of the loop:

```rust
// Each call to `next_line` returns either `Some(line)`, where
// `line` is a line of input, or `None`, if we've reached the end of
// the input. Return the first line that starts with "answer: ".
// Otherwise, return "answer: nothing".
let answer = loop {
    if let Some(line) = next_line() {
        if line.starts_with("answer: ") {
            break line;
        }
    } else {
        break "answer: nothing";
    }
};
```

A loop can be **labeled** with a lifetime. In the following example, `'search:` is a label for the outer `for` loop. Thus, `break 'search` exits that loop, not the inner loop:

```rust
'search:
for room in apartment {
    for spot in room.hiding_spots() {
        if spot.contains(keys) {
            println!("Your keys are {} in the {}.", spot, room);
            break 'search;
        }
    }
}
```

A `break` can have both a label and a value expression. Labels can also be used with `continue`.

## `return` Expressions

`return` without a value is shorthand for `return ()`.

We used the `?` operator to check for errors after calling a function that can fail:

```rust
let output = File::create(filename)?;
let output = match File::create(filename) {
    Ok(f) => f,
    Err(err) => return Err(err)
};
```

Expressions that don’t finish normally are assigned the special type `!`, and they’re exempt from the rules about types having to match. You can see `!` in the function signature of `std::process::exit()`:

```rust
fn exit(code: i32) -> !
```

The `!` means that `exit()` never returns. It’s a ***divergent function***.

You can write divergent functions of your own using the same syntax, and this is perfectly natural in some cases:

```rust
fn serve_forever(socket: ServerSocket, handler: ServerHandler) -> ! {
    socket.listen();
    loop {
        let s = socket.accept();
        handler.handle(s);
    }
}
```

Rust then considers it an error if the function can return normally.

## Function and Method Calls

`.` operator is ease with the types.

**Syntax** for generic types:

```rust
return Vec::<i32>::with_capacity(1000);  // ok, using ::<

let ramp = (0 .. n).collect::<Vec<i32>>();  // ok, using ::<
```

The symbol `::<...>` is affectionately known in the Rust community as the *turbofish*.

## Fields and Elements

```rust
ame.black_pawns   // struct field
coords.1           // tuple element
pieces[i]          // array element
```

Expressions like these three are called *lvalues*, because they can appear on the left side of an assignment.

Extracting a slice from an array or vector is straightforward:

```rust
let second_half = &game_moves[midpoint .. end];
```

The `..=` operator produces *end-inclusive* (or *closed*) ranges, which do include the end value:

```rust
..= b    // RangeToInclusive { end: b }
a ..= b  // RangeInclusive::new(a, b)
```

## Arithmetic, Bitwise, Comparison, and Logical Operators

Rust uses `!` instead of `~` for bitwise NOT.

Bit shifting is always sign-extending on signed integer types and zero-extending on unsigned integer types. Since Rust has unsigned integers, it does not need an unsigned shift operator, like Java’s `>>>` operator.

Bitwise operations have higher precedence than comparisons, unlike C, so if you write `x & BIT != 0`, that means `(x & BIT) != 0`, as you probably intended. This is much more useful than C’s interpretation, `x & (BIT != 0)`, which tests the wrong bit!

## Type Casts

Rust does not have C’s increment and decrement operators `++` and `--`.

Numbers may be cast from any of the built-in numeric types to any other.

Values of type `bool` or `char`, or of a C-like `enum` type, may be cast to any integer type.

***

Some casts involving unsafe pointer types are also allowed.

* Values of type `&String` auto-convert to type `&str` without a cast.
* Values of type `&Vec<i32>` auto-convert to `&[i32]`.
* Values of type `&Box<Chessboard>` auto-convert to `&Chessboard`.

These are called ***deref coercions***, because they apply to types that implement the `Deref` built-in trait. The purpose of `Deref` coercion is to make smart pointer types, like `Box`, behave as much like the underlying value as possible. Using a `Box<Chessboard>` is mostly just like using a plain `Chessboard`, thanks to `Deref`.

## Closures

Rust has *closures*, lightweight function-like values. A closure usually consists of an argument list, given between vertical bars, followed by an expression:

```rust
let is_even = |x| x % 2 == 0;
```
