I'm trying to implement a commonly used pattern - using the result of a previous loop iteration in the next loop iteration. For example, to implement pagination where you need to give the id of the last value on the previous page.
struct Result {
str: String,
}
fn main() {
let times = 10;
let mut last: Option<&str> = None;
for i in 0..times {
let current = do_something(last);
last = match current {
Some(r) => Some(&r.str.to_owned()),
None => None,
};
}
}
fn do_something(o: Option<&str>) -> Option<Result> {
Some(Result {
str: "whatever string".to_string(),
})
}
However, I'm not sure how to actually get the value out of the loop. Currently, the compiler error is temporary value dropped while borrowed
(at &r.str.to_owned()
), though I made many other attempts, but to no avail.
The only way I found to actually get it working is to create some sort of local tmp_str
variable and do a hack like this:
match current {
Some(r) => {
tmp_str.clone_from(&r.str);
last = Some(&tmp_str);
}
None => {
last = None;
}
}
But that doesn't feel like it's the way it's supposed to be done.
In your code, it remains unclear who the owner of the String
referenced in last: Option<&str>
is supposed to be. You could introduce an extra mutable local variable that owns the string. But then you would have two variables: the owner and the reference, which seems redundant. It would be much simpler to just make last
the owner:
struct MyRes {
str: String,
}
fn main() {
let times = 10;
let mut last: Option<String> = None;
for _i in 0..times {
last = do_something(&last).map(|r| r.str);
}
}
fn do_something(_o: &Option<String>) -> Option<MyRes> {
Some(MyRes {
str: "whatever string".to_string(),
})
}
In do_something
, you can just pass the whole argument by reference, this seems more likely to be what you wanted. Also note that naming your own struct Result
is a bad idea, because Result
is such a pervasive trait built deeply into the compiler (?
-operator etc).
Follow-up question: Option<&str>
or Option<String>
?
Both Option<&str>
and Option<String>
have different trade-offs. One is better for passing string literals, other is better for passing owned String
s. I'd actually propose to use neither, and instead make the function generic over type S
that implements AsRef<str>
. Here is a comparison of various methods:
fn do_something(o: &Option<String>) {
let _a: Option<&str> = o.as_ref().map(|r| &**r);
let _b: Option<String> = o.clone();
}
fn do_something2(o: &Option<&str>) {
let _a: Option<&str> = o.clone(); // do you need it?
let _b: Option<String> = o.map(|r| r.to_string());
}
fn do_something3<S: AsRef<str>>(o: &Option<S>) {
let _a: Option<&str> = o.as_ref().map(|s| s.as_ref());
let _b: Option<String> = o.as_ref().map(|r| r.as_ref().to_string());
}
fn main() {
let x: Option<String> = None;
let y: Option<&str> = None;
do_something(&x); // nice
do_something(&y.map(|r| r.to_string())); // awkward & expensive
do_something2(&x.as_ref().map(|x| &**x)); // cheap but awkward
do_something2(&y); // nice
do_something3(&x); // nice
do_something3(&y); // nice, in both cases
}
Note that not all of the above combinations are very idiomatic, some are added just for completeness (e.g. asking for AsRef<str>
and then building an owned String
out of seems a bit strange).