What is the "()" type in Rust?
Asked Answered
S

4

13

As a simple exercise to learn Rust, I've decided to implement a simple binary search:

pub fn binary_search(arr: &[i32], key: i32) -> usize {
    let min: usize = 0;
    let max: usize = arr.len();
    while max >= min {
        let mid: usize = (max - min) / 2 as usize;
        if key == arr[mid] {
            mid as usize
        }

        if key < arr[mid] {
            min = mid + 1;
            continue;
        }

        max = mid - 1;
    }
    -1 as usize
}

#[cfg(test)]
mod tests {
    use super::binary_search;

    #[test]
    fn binary_search_works() {
        let arr: [i32; 8] = [1, 2, 3, 4, 5, 6, 7, 8];
        let index: usize = binary_search(&arr, 2);
        assert_eq!(1, index);
    }
}

At build time, I get this error which I do not understand. What is the () type? The variable mid is always usize but even with the as cast I'm getting this compilation error:

error: mismatched types [E0308]
            mid as usize
            ^~~~~~~~~~~~
help: run `rustc --explain E0308` to see a detailed explanation
note: expected type `()`
note:    found type `usize`
Shrier answered 29/7, 2016 at 16:18 Comment(1)
#24842771Jinnyjinrikisha
F
12

() is the unit type, analogous to a void return type in other languages.

You're getting it here:

if key == arr[mid] {
    mid as usize
}

Rust is expecting that if expression to return (), but you're returning usize for that expression. Since virtually everything in Rust is an expression, you can usually implicit return like you're trying to here, but in this specific case you can't because the if expression is not the only expression in the while expression. You could fix the immediate problem by using return mid as usize; instead.

Fabiano answered 29/7, 2016 at 16:24 Comment(0)
H
14

() is the unit type or singleton type: it has a single value, also denoted ().

I personally view it as a tuple with 0 elements.

Where C or C++ would use void (which has no value) to indicate the return type of a function which returns nothing interesting, Rust uses () instead. This is much nicer to meta-programming, as () is a regular type which accepts values, can be mutated, borrowed, etc...


Regarding your specific code sample:

if key == arr[mid] {
    mid as usize
}

is an expression of type () (because there is no else branch) yet you are attempting to have the if block evaluate to mid as usize which has the type usize thus the compiler notices the mismatch.

You want to use a return here:

if key == arr[mid] {
    return mid as usize;
}
Haymes answered 29/7, 2016 at 16:25 Comment(1)
I personally think this is the better answer because it correctly addresses why the if expects the unit type - the lack of else instead of it not being the only expression in the loop.Righthand
F
12

() is the unit type, analogous to a void return type in other languages.

You're getting it here:

if key == arr[mid] {
    mid as usize
}

Rust is expecting that if expression to return (), but you're returning usize for that expression. Since virtually everything in Rust is an expression, you can usually implicit return like you're trying to here, but in this specific case you can't because the if expression is not the only expression in the while expression. You could fix the immediate problem by using return mid as usize; instead.

Fabiano answered 29/7, 2016 at 16:24 Comment(0)
R
1

There are two issues here

  1. The return type ()
  2. Returning from a function early

Regarding your specific code sample:

if key == arr[mid] {
    mid as usize
}

By omitting the semicolon from the end of this expression you're trying to return a type ().

"Why?" you might ask. See this answer, but long story short, it makes the core language simpler by avoiding Option types in if statements.

24 | |         };
   | |_________^ expected `()`, found integer
   |
   = note: `if` expressions without `else` evaluate to `()`
   = help: consider adding an `else` block that evaluates to the expected type

For more information about this error, try `rustc --explain E0317`.

Even adding an else statement here wouldn't help you because what you're trying to do is to return from the function early, not return the value of the expression. Remember any non-semicolon-terminated expression { expression } returns its value to the surrounding context which is the body of the function in this case.

Using return causes the function to return early, which is what you want.

if key == arr[mid] {
    return mid as usize;
}

Note that the reason you don't need a return function at the end of the function

-1 as usize

is because it is returning to the surrounding context: in this case the place where the function was called.

Revalue answered 30/3, 2022 at 17:29 Comment(0)
R
0

I was trying to run your code and it doesn't really seem to work. Unit tests may run forever when checking all values, like:

assert_eq!(1, index); assert_eq!(2, index); assert_eq!(3, index); ... assert_eq!(8, index);

Are you sure this algorithm is coded correctly? Not to mention warnings with regard to let vs let mut, etc.

Retroversion answered 26/9, 2023 at 11:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.