I'm struggling to write a recursive algorithm in Rust. With the following code:
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)
}
I get:
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`.
However, if I change the last statement to:
Ok(expanded)
it works, but it's not longer recursive.
I understand the idea that I'm trying to return a value borrowed from a local frame, but I think this is safe based on the second example. How can I tell the compiler that?
Note: I'm using AsRef
because I want to be able to pass both a Vec<String>
and Vec<&str>
to expand_symbols()
. Maybe I need to forget about that?
With Ok(expanded)
the variable expanded
is moved out of the function, meaning no reference to it existing after the function returned. So, the second sample, if you meant by Ok(expanded)
, is not same as the original one.
To address the issue I think you can pass a mutable reference to symbols
as the first parameter of the function, and do in-place edit on it instead of creating a new local vector, 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)
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.