【问题标题】:How do I return local data with a recursive function in Rust?如何在 Rust 中使用递归函数返回本地数据?
【发布时间】:2021-11-28 12:03:39
【问题描述】:

我正在努力用 Rust 编写递归算法。使用以下代码:

use std::collections::HashMap;

enum Error {
    Bad,
    ReallyBad,
}

fn expand_symbols<'a, T: AsRef<str>>(
    symbols: &'a [T],
    ops: &HashMap<String, String>,
    user_ops: &'a HashMap<String, String>,
) -> std::result::Result<Vec<&'a str>, Error> {
    if symbols.iter().all(|x| ops.get(x.as_ref()).is_some()) {
        let symbols = symbols.iter().map(|x| x.as_ref()).collect();
        return Ok(symbols);
    }

    let mut expanded: Vec<&str> = vec![];
    for s in symbols {
        let s = s.as_ref();
        if ops.contains_key(s) || s.parse::<i32>().is_ok() {
            expanded.push(s);
        } else {
            let mut resolved = user_ops
                .get(s)
                .ok_or(Error::Bad)?
                .split_ascii_whitespace()
                .collect::<Vec<_>>();
            expanded.append(&mut resolved);
        }
    }
    expand_symbols(&expanded, ops, user_ops)
}

我明白了:

error[E0515]: cannot return value referencing local variable `expanded`
  --> src/main.rs:32:5
   |
32 |     expand_symbols(&expanded, ops, user_ops)
   |     ^^^^^^^^^^^^^^^---------^^^^^^^^^^^^^^^^
   |     |              |
   |     |              `expanded` is borrowed here
   |     returns a value referencing data owned by the current function

For more information about this error, try `rustc --explain E0515`.

但是,如果我将最后一条语句更改为:

Ok(expanded)

它可以工作,但它不再是递归的。

我理解我试图返回从本地框架借来的值的想法,但我认为根据第二个示例这是安全的。我怎么能告诉编译器呢?

注意:我使用AsRef 是因为我希望能够将Vec&lt;String&gt;Vec&lt;&amp;str&gt; 都传递给expand_symbols()。也许我需要忘记这一点?

【问题讨论】:

  • 我在三个地方看到'a:两个参数和一个返回值。你真的希望这三个生命周期都相同吗?您的算法中是否有理由必须这样做?
  • 不,但编译器也告诉了我。 :) 我相信因为来自symbolsuser_ops 的元素都可以在返回值中结束。

标签: rust


【解决方案1】:

对于Ok(expanded),变量expanded 被移出函数,这意味着在函数返回后不存在对它的引用。所以,第二个样本,如果您指的是Ok(expanded),与原始样本不同。

为了解决这个问题,我认为您可以传递对 symbols 的可变引用作为函数的第一个参数,并对其进行就地编辑,而不是创建新的本地向量 explanded

fn expand_symbols<'a>(
    symbols: &'a mut Vec<&'a str>,
    ops: &HashMap<String, String>,
    user_ops: &'a HashMap<String, String>,
) -> std::result::Result<&'a Vec<&'a str>, Error> {
    if symbols.is_empty() || symbols.iter().all(|x| ops.get(*x).is_some()) {
         return Ok(symbols);
    }

    let mut unresolved: Vec<&str> = vec![]; 
    let mut i = 0;
    while i < symbols.len() {
        let s = symbols[i];
        if ops.contains_key(s) || s.parse::<i32>().is_ok() {
            i += 1;
        } else {
            unresolved.push(symbols.remove(i));
        }
    }

    for s in unresolved.iter() {
        let mut resolved = user_ops
            .get(*s)
            .ok_or(Error::Bad)?
            .split_ascii_whitespace()
            .collect::<Vec<_>>();
        symbols.append(&mut resolved);
    };

    expand_symbols(symbols, ops, user_ops)
}

playground

【讨论】:

    猜你喜欢
    • 2017-11-02
    • 2015-03-09
    • 1970-01-01
    • 2017-10-29
    • 2021-07-09
    • 1970-01-01
    • 2022-01-16
    • 1970-01-01
    相关资源
    最近更新 更多