user1002430
user1002430

Reputation:

How to use ? and catch in Rust?

It seems that ? and catch have been accepted into Rust, but I am not able to use it properly:

let x = catch {
    1
}

I think this should give me Ok(1). Instead, I get the error:

error: expected identifier, found `1`
  --> src/main.rs:15:9
   |
15 |         1
   |         ^

Is this syntax not yet supported in Rust, or is there a problem with my code?

Upvotes: 2

Views: 6616

Answers (2)

Matthieu M.
Matthieu M.

Reputation: 299880

TL;DR: The RFC is accepted, but your syntax is slightly off (unfortunately) and the feature is still gated.

See Alec's excellent answer on how to actually use catch.


I encourage you to read the full error log:

error: expected identifier, found `1`
 --> <anon>:2:21
  |
2 |     let x = catch { 1 };
  |                     ^

error[E0422]: cannot find struct, variant or union type `catch` in this scope
 --> <anon>:2:13
  |
2 |     let x = catch { 1 };
  |             ^^^^^ not found in this scope

error: aborting due to 2 previous errors

The clue is in the second error message:

cannot find struct, variant or union type catch in this scope

which really lets us know that catch is not recognized as a keyword by the compiler.

Since catch looks like any regular word, what happens is that the compiler attempts to parse this as building a struct or enum. Indeed, the syntax for building a struct or enum is:

struct X { name: i32 }

let x = X { name: 1 };

Therefore, the compiler sees <identifier> { and expects it to be followed by a list of <identifier>: <expression>. It reads 1, which is not an identifier, and reports the error that 1 is not an identifier.

Upvotes: 5

Alec
Alec

Reputation: 32309

This is going to sound very dumb, because it kind of is. You need to have

#![feature(catch_expr)]

fn main() {
    let x = do catch {
        1
    };
}

Basically, catch, like default and union, cannot be made a keyword without breaking backwards compatibility. Since Rust has tried to guarantee that any code on 1.x will still work on 1.y, introducing default, union and now catch into the grammar has been all about figuring out the conflicts. For union and default, there are none - identifiers are never expected in those positions.

For catch, catch { 1 } can also be interpreted as a struct literal. Unless you require do (a reserved keyword) occur before catch - then there is no ambiguity. Yes, this is ugly, and everyone knows it.

Hopefully these nightmares go away when 2.0 comes around and we can break backwards compatibility. Quoted from the rust-internals discussion around the grammar woes of catch:

There's a growing list of other syntax we would ultimately like to repurpose in this way, but we generally avoid breaking the ability to run code that worked on 1.x on 1.y where y > x except in cases where the code was exploiting a compiler bug or was just a terrifically rare construction. Our stability guarantees demand we wait until 2.0 for most of these.

Upvotes: 7

Related Questions