Is there a Rust equivalent to C++'s operator bool() to convert a struct into a boolean?

Viewed 405

In C++, we can overload operator bool() to convert a struct to bool:

struct Example {
    explicit operator bool() const {
        return false;
    }
};

int main() {
    Example a;
    if (a) { /* some work  */ }
}

Can we do something simple (and elegant) in Rust so to:

pub struct Example {}

fn main() {
    let k = Example {};
    if k {
        // some work
    }
}
4 Answers

There's no direct equivalent of operator bool(). A close alternative would be to implement From (which will also implement Into) and call the conversion explicitly:

pub struct Example;

impl From<Example> for bool {
    fn from(_other: Example) -> bool {
        false
    }
}

fn main() {
    let k = Example;
    if k.into() {
        // some work
    }
}

This will take ownership of Example, meaning you can't use k after it's been converted. You could implement it for a reference (impl From<&Example> for bool) but then the call site becomes uglier ((&k).into()).

I'd probably avoid using From / Into for this case. Instead, I'd create a predicate method on the type. This will be more readable and can take &self, allowing you to continue using the value.

See also:

Rust does not have C++'s implicit type conversion via operator overloading. The closest means of implicit conversion is through a Deref impl, which provides a reference of a different type.

What is possible, albeit not necessarily idiomatic, is to implement the not operator ! so that it returns a boolean value, and perform the not operation twice when needed.

use std::ops::Not;

pub struct Example;

impl Not for Example {
    type Output = bool;
    
    fn not(self) -> bool { false }
}

fn main() {
    let k = Example;
    if !!k {
        println!("OK!");
    } else {
        println!("WAT");
    }
}

Playground

You have a few options, but I'd go for one of these:

Into<bool> (From<Example>)

If your trait conceptually represents a bool, but maybe with some extra metadata, you can implement From<Example> for bool:

impl From<Example> for bool {
    fn from(e: Example) {
        // perform the conversion
    }
}

Then you can:

fn main() {
    let x = Example { /* ... */ };
    if x.into() {
        // ...
    }
}

Custom method

If your type doesn't really represent a boolean value, I'd usually go for an explicit method:

impl Example {
    fn has_property() -> bool { /* ... */ }
}

This makes it more obvious what the intent is, for example, if you implemented From<User> for bool:

fn main() {
    let user = User { /* ... */  };

    if user.into() {
        // when does this code get run??
    }

    // compared to
    if user.logged_in() {
        // much clearer
    }
}

You can implement std::ops::Deref with the bool type. If you do that, you have to call *k to get the boolean.

This is not recommended though, according to the Rust documentation:

On the other hand, the rules regarding Deref and DerefMut were designed specifically to accommodate smart pointers. Because of this, Deref should only be implemented for smart pointers to avoid confusion.

struct Example {}

impl std::ops::Deref for Example {
    type Target = bool;

    fn deref(&self) -> &Self::Target {
        &true
    }
}

fn main() {
    let k = Example {};
    if *k {
        // some work
    }
}

Playground

Related