9

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 } } 
3
  • 7
    Another fine example why C++ is such a "dangerous" language. Even if Example is not a boolean type, it is used as such. So the real conversion is hidden, and from the source it is not clear what is meant. :-( Commented Nov 24, 2021 at 14:31
  • 3
    What is your use case for this? Is this really a type conversion, or do you want to assign a "truthiness" to a data type, e.g. false means empty container and true means non-empty? The idiomatic way to do this in Rust depends on your actual use case. Commented Nov 24, 2021 at 15:02
  • While that may be "simple", I'd argue that it's not "elegant". What does if k even mean? You're better off implementing a specific method that returns a boolean and calling that -- eg if k.has_data() Commented Nov 24, 2021 at 16:40

4 Answers 4

12

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:

Sign up to request clarification or add additional context in comments.

4 Comments

The API guidelines state that Into should never be implemented. Since this is a rather highly voted answer, it should probably be implemented with the idiomatic From<Example> for bool?
@sebpuetz a good point. It's less needed since a few Rust versions back, but we still use From for consistency.
It's not only for consistency. Implementing From<T> for U gives you Into<U> for T for free because of the blanket impl, while implementing Into<U> for T directly doesn't give you a From impl.
@SvenMarnach my point is that relatively recent Rust versions removed the entire reason that both From and Into existed in the first place. If the standard library were designed today, there would only be Into. That wasn't true in Rust 1.0.
4

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

Comments

3

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 } } 

Comments

2

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

1 Comment

The OP's type does not have a boolean field.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.