Hello peeps,
I have a structure that needs to periodically get an element from a cyclic pattern.
That is, my structure will be initialized with a pattern (let's say "abc"), and at various points during the struct lifetime I want to get the next element of the pattern (first time I'll get 'a', then 'b', then 'c', then 'a' again, then 'b'... ad infinitum).
My idea is therefore to create an iterator out of the cycle
method and store that. Then I'll just need to call next()
on it each time I want a new element! Unfortunately, by doing that I've opened the dread can of lifetime worms.
Here is an initial code that fails:
struct Foo {
cycle: Box<dyn Iterator<Item=char>>,
}
impl Foo {
fn new(pattern: &str) -> Self {
Self {
cycle: Box::new(pattern.chars().cycle()),
}
}
}
Predictably, this fails:
error: lifetime may not live long enough
--> src/main.rs:9:20
|
7 | fn new(pattern: &str) -> Self {
| - let's call the lifetime of this reference `'1`
8 | Self {
9 | cycle: Box::new(pattern.chars().cycle()),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cast requires that `'1` must outlive `'static`
Of course I thought, iterators don't own the thing they're iterating over! So my next idea was to clone the pattern and also store it as a String next to the iterator, that way they'll have the same lifetime:
struct Foo {
pattern: String,
cycle: Box<dyn Iterator<Item=char>>,
}
impl Foo {
fn new(pattern: &str) -> Self {
let pattern = pattern.to_string();
Self {
pattern,
cycle: Box::new(pattern.chars().cycle()),
}
}
}
But this doesn't work either:
--> src/main.rs:12:29
|
12 | cycle: Box::new(pattern.chars().cycle()),
| ---------^^^^^^^^^^^^^^^---------
| | |
| | borrowed value does not live long enough
| cast requires that `pattern` is borrowed for `'static`
13 | }
14 | }
| - `pattern` dropped here while still borrowed
error[E0382]: borrow of moved value: `pattern`
--> src/main.rs:12:29
|
9 | let pattern = pattern.to_string();
| ------- move occurs because `pattern` has type `String`, which does not implement the `Copy` trait
10 | Self {
11 | pattern,
| ------- value moved here
12 | cycle: Box::new(pattern.chars().cycle()),
| ^^^^^^^^^^^^^^^ value borrowed here after move
|
= note: borrow occurs due to deref coercion to `str`
I'm at a loss, I don't know how to express this concept. What would be a clean way to achieve that I'm trying to do? Worst comes to worst, I can always store a mutable index and play with modulos, but I'd rather take advantage of high level concepts.
Cheers,