在处理嵌套的 Option 类型时,如何减少代码的嵌套?

Ale*_*kiy 3 rust

我是 Rust 的新手,我想减少代码的嵌套。以这个 C# 代码为例:

for (int i = 0; i < 100; i++)
{
    var obj = arr[i];
    if (obj != null)
    {
        var something = obj.Something;
        if (something == null)
        {
            if (i % 3 == 0)
                Console.WriteLine(i);
            break;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

ReSharper 建议重写它以减少嵌套:

for (int i = 0; i < 100; i++)
{
    var obj = arr[i];
    if (obj == null)
        continue;
    var something = obj.Something;
    if (something != null)
        continue;
    if (i % 3 == 0)
        Console.WriteLine(i);
    break;
}
Run Code Online (Sandbox Code Playgroud)

有没有办法在 Rust 中做同样的事情?如果我有嵌套Option<Option<Option<T>>>等等,我应该写一些类似的东西:

fn main() {
    for i in 1..100 {

        if let Some(data) = some_data::get_some_data() {
            if let Some(result) = data.some_work(i) {
                if result > 80 {
                    break;
                }
            }
        }

        println!("{}", i);
    }
}

mod some_data
{
    pub struct SomeData {
        value : i32
    }

    impl SomeData {
        pub fn some_work(&self, i : i32) -> Option<i32> {
            Some(self.value + i)
        }
    }

    pub fn get_some_data() -> Option<SomeData> {
        Some(SomeData { value : 50 })
    }
}
Run Code Online (Sandbox Code Playgroud)

这个例子是简化的,但它显示了核心问题。

fjh*_*fjh 5

你可以做一些事情。一种选择是continueNone手臂上使用匹配项,类似于您的 C# 代码:

fn main() {
    for i in 1..100 {

        let data = match some_data::get_some_data() {
            None => continue,
            Some(data) => data
        };
        let result = match data.some_work(i) {
            None => continue,
            Some(result) => result
        };

        if result > 80 {
            break;
        }

        println!("{}", i);
    }
}
Run Code Online (Sandbox Code Playgroud)

正如@Cecilio Pardo 建议的那样,您可以做的另一件事是使用is_thenOption类型的方法来链接您的操作:

fn main() {
    for i in 1..100 {

        if let Some(result) = some_data::get_some_data()
                              .and_then(|data| data.some_work(i)) {
            if result > 80 {
                break;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)