hansaplast
hansaplast

Reputation: 11603

Can I combine variable assignent with an if?

I have this code:

let fd = libc::creat(path, FILE_MODE);
if fd < 0 {
    /* error */
}

the equivalent in C is shorter:

if ((fd = creat(path, FILE_MODE)) < 0) {
    /* error */
}

can I do a similar thing in Rust? I tried to map it to if let but it looks like handling Options.

Upvotes: 3

Views: 134

Answers (1)

Lukas Kalbertodt
Lukas Kalbertodt

Reputation: 89016

No, it's not possible by design. let bindings are one of the two non-expression statements in Rust. That means that the binding does not return any value that could be used further.

Bindings as expressions don't make a whole lot of sense in Rust in general. Consider let s = String::new(): this expression can't return String, because s owns the string. Or what about let (x, _) = get_tuple()? Would the expression return the whole tuple or just the not-ignored elements? So ⇒ let bindings aren't expressions.

About the if let: Sadly that won't work either. It just enables us to test if a destructuring works or to put it in other words: destructure a refutable pattern. This doesn't only work with Option<T>, but with all types.


If you really want to shorten this code, there is a way: make c_int easily convertible into a more idiomatic type, like Result. This is best done via extension trait:

trait LibcIntExt {
    fn to_res(self) -> Result<u32, u32>;
}

impl LibcIntExt for c_int {
    fn to_res(self) -> Result<u32, u32> {
        if self < 0 {
            Err(-self as u32)
        } else {
            Ok(self as u32)
        }
    }
}

With this you can use if let in the resulting Result:

if let Err(fd) = libc::creat(path, FILE_MODE).to_res() {
    /* error */
}

Upvotes: 5

Related Questions