use std::collections::HashMap;
use std::collections::BTreeSet;
struct DataRoot {
entries: Vec<Entry>
}
impl DataRoot {
pub fn columns<'this>(&'this self) -> impl Iterator<Item = &'this str> {
let mut dynamic_columns = BTreeSet::new();
for entry in &self.entries {
dynamic_columns.extend(entry.dynamic_coluimns());
}
// This combines 'this and 'static, and I want the result to be 'this
// (which is *shorter*)
// This doesn't work for some reason, why? And what can be done about it?
Entry::leading_columns()
.chain(dynamic_columns.into_iter())
.chain(Entry::trailing_columns())
}
}
struct Entry {
// Various fixed fields here...
// Other fields that are specific to this case, capture them dynamically
// #[serde(flatten)]
other: HashMap<String, String>
}
impl Entry {
fn leading_columns() -> impl Iterator<Item = &'static str> {
["Crate name", "URL", "Maintained", "License", "Std"].into_iter()
}
fn dynamic_coluimns(&self) -> impl Iterator<Item = &str> {
self.other.keys().map(|s| s.as_str())
}
fn trailing_columns() -> impl Iterator<Item = &'static str> {
["Notes"].into_iter()
}
}
Playground link:
The error I get is:
Compiling playground v0.0.1 (/playground)
error: lifetime may not live long enough
--> src/lib.rs:19:9
|
9 | pub fn columns<'this>(&'this self) -> impl Iterator<Item = &'this str> {
| ----- lifetime `'this` defined here
...
19 | / Entry::leading_columns()
20 | | .chain(dynamic_columns.into_iter())
21 | | .chain(Entry::trailing_columns())
| |_____________________________________________^ returning this value requires that `'this` must outlive `'static`
|
help: to declare that `impl Iterator<Item = &'this str>` captures data from argument `self`, you can add an explicit `'this` lifetime bound
|
9 | pub fn columns<'this>(&'this self) -> impl Iterator<Item = &'this str> + 'this {
| +++++++
error: could not compile `playground` (lib) due to 1 previous error
- Adding the recommended
+ 'this
does not help. - Just returning
dynamic_columns.into_iter()
does work (as expected). - Making leading_columns & trailing_columns instance methods and lying about the lifetimes of the static fields "works", but then I need an actual instance to call them on.
Not sure what is going on here or how to fix it properly.
EDIT: Even rewriting it in terms of a temporary vector doesn't work:
let mut values = vec![];
values.extend(Entry::leading_columns());
values.extend(dynamic_columns.into_iter());
values.extend(Entry::trailing_columns());
values.into_iter()
This suggests that it isn't just about chain, but some more fundamental limitation of Rust. Is there a way to shorten the lifetime of leading and trailing columns such that this code works?
Even mapping to_string
on the &str
after the chain doesn't work (but strangely enough doing it before the chaining does work)... That one makes even less sense to me.