#[derive(Debug)]
struct UvOpts {
from: Option<String>,
with: Box<[(String, bool)]>,
}
fn install(opts: &UvOpts) {
let from = ["--from"]
.into_iter()
.chain(opts.from.iter().map(String::as_str))
.filter(|_| opts.from.is_some());
let mut with_enabled_commands = Vec::new();
let mut with_disabled_commands = Vec::new();
opts.with.iter().for_each(|(key, opt)| {
if *opt {
with_enabled_commands.push(key.clone());
} else {
with_disabled_commands.push(key.clone());
}
});
let with_disabled = with_disabled_commands.join(",");
let with_disabled_opts = ["--with", with_disabled.as_str()]
.into_iter()
.filter(|_| !with_disabled_commands.is_empty());
let command = ["uv", "tool", "install"]
.into_iter()
.chain(from)
.chain(with_disabled_opts);
drop(command);
}
This function fails to borrow check, while saying that with_disabled does not live long enough. I'm unable to make much out of the error, and it doesn't really make sense to me. Here's a link to the playground
My question mainly is this, why does the object not live long enough? I fail to see why it's the case. What does the from field have to do with the destructor of with_disabled?
Here's the full error message:
Compiling playground v0.0.1 (/playground)
error[E0597]: `with_disabled` does not live long enough
--> src/main.rs:35:41
|
34 | let with_disabled = with_disabled_commands.join(",");
| ------------- binding `with_disabled` declared here
35 | let with_disabled_opts = ["--with", with_disabled.as_str()]
| ^^^^^^^^^^^^^ borrowed value does not live long enough
...
46 | }
| -
| |
| `with_disabled` dropped here while still borrowed
| borrow might be used here, when `from` is dropped and runs the destructor for type `Filter<std::iter::Chain<std::array::IntoIter<&str, 1>, std::option::IntoIter<&str>>, {closure@src/main.rs:22:17: 22:20}>`
|
= note: values in a scope are dropped in the opposite order they are defined
For more information about this error, try `rustc --explain E0597`.
error: could not compile `playground` (bin "playground") due to 1 previous error
The error about “dropped here while still borrowed” indicates that the compiler thinks that with_disabled needs to be borrowed for a lifetime that outlives the function call. Which does not make sense. I’m not sure what is going on, but it feels more like a type-inference problem than a borrow-checking problem — you've got 3 different data sources (string literals, borrowed input, borrowed locals) and it seems like it must be erroneously assuming the type of an iterator item has to have the lifetime from the borrowed input instead of a local lifetime. In particular, just re-ordering your code so that from is last succeeds:
fn install(opts: &UvOpts) {
let mut with_enabled_commands = Vec::new();
let mut with_disabled_commands = Vec::new();
opts.with.iter().for_each(|(key, opt)| {
if *opt {
with_enabled_commands.push(key.clone());
} else {
with_disabled_commands.push(key.clone());
}
});
let with_disabled = with_disabled_commands.join(",");
let with_disabled_opts = ["--with", with_disabled.as_str()]
.into_iter()
.filter(|_| !with_disabled_commands.is_empty());
let from = ["--from"]
.into_iter()
.chain(opts.from.iter().map(String::as_str))
.filter(|_| opts.from.is_some());
let command = ["uv", "tool", "install"]
.into_iter()
.chain(from)
.chain(with_disabled_opts);
drop(command);
}
This is probably a compiler bug, and also probably hard to fix.
I recommend against enabling the clippy::nursery lint group, especially to beginners. nursery is the place for lints that have significant flaws such as false positives that might give incorrect advice.
pedantic is debatable, but clippy's default settings are a better place to start, in my opinion. You don't need to configure anything, just to run cargo clippy instead of cargo check. (If you don't do that, then the configuration will have no effect.)