'Is there an idiomatic way of chaining Option in Rust?

When deserializing deeply nested structures (e.g. from JSON), it's not uncommon to have to traverse multiple Option types.

For example:

let foo = Foo {
    x: Some(Bar {
        y: Some(Baz {
            z: Some(42),
        })
    })
};

Is there an idiomatic way of chaining Option to access deeply nested values?

So far I have the following, but neither are as concise as foo.x?.y?.z in other languages that support optional-chaining:

let z = foo.x.as_ref().and_then(|x| x.y.as_ref()).and_then(|y| y.z);
let z = foo.x.as_ref().and_then(|x| x.y.as_ref()?.z);
let z = (|| foo.x.as_ref()?.y.as_ref()?.z)();

It looks like the try_block feature might be a good fit, but it's currently unstable.

let z = try { foo.x.as_ref()?.y.as_ref()?.z };


Solution 1:[1]

As you say, the try block would be perfect for this.

In the meantime you can take advantage of the fact that ? works in functions, and wrap your expression in a closure and call it:

let z = (|| foo.x.as_ref()?.y.as_ref()?.z )();

You can write a simple macro to make it a bit nicer:

macro_rules! tryit {
    ($($e: tt)+) => {
        (|| { $($e)+ })()
    }
}

Which works basically the same as the try block:

let z = tryit! { foo.x.as_ref()?.y.as_ref()?.z };

Solution 2:[2]

Another option if you don't like the immediately called closure is to use a crate like map_for or mdo. Example with map_for:

use map_for::option::FlatMap;
let z = map_for!{
    x <- foo.x.as_ref();
    y <- x.y.as_ref();
    => y.z }:

Disclaimer: I wrote the map_for crate.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Jmb