How to shorten the lifetime of each item in IntoIterator? - rust

The following is the code:
struct A;
fn f<'a, I>(default_args: I)
where
I: IntoIterator<Item = &'a A>,
{
{
let a1 = A;
let more_args = [&a1];
{
let i = default_args.into_iter();
let i = i.chain(more_args);
// I will use `i` here.
}
}
// I will NOT use `*_args` here.
}
The following is error:
error[E0597]: `a1` does not live long enough
--> src\main.rs:27:26
|
21 | fn f<'a, I>(default_args: I)
| -- lifetime `'a` defined here
...
27 | let more_args = [&a1];
| ^^^ borrowed value does not live long enough
...
30 | let i = i.chain(more_args);
| ------------------ argument requires that `a1` is borrowed for `'a`
...
33 | }
| - `a1` dropped here while still borrowed
For more information about this error, try `rustc --explain E0597`.
I want to get a new default_args_2 from default_args, where the Item inside default_args_2 has a shorter lifetime, as long as it valid inside the function.

You can add a little (almost) noop .map(|v| v):
let i = default_args.into_iter().map(|v| v);
The problem was that the iterator item types have to match, and therefore the chained iterator has to also yield &'a T, which it does not (it yields a shorter lifetime).
Since you don't really need to use the items for 'a, the trick of the noop map() is to insert a subtyping point: Now, the closure inside map() (conceptually) converts the &'a T, to a &'shorter_lifetime T, which is fine since 'a: 'shorter_lifetime, but now the chained iterator can produce the desired item type.
Putting it differently, you cannot convert impl Iterator<Item = &'a T> into impl Iterator<Item = &'shorter_lifetime T> (as it may not be covariant over the lifetime), but you can convert &'a T to &'shorter_lifetime T, and we use that fact because from the outside we have impl Iterator<Item = &'a T>, but inside map()'s closure we got &'a T.

Related

How to establish relation with respect to higher ranked trait bounds

I am trying to create a high order function which takes in (a function that takes &str and returns iterator of &str). What I am having difficulty is to relate lifetime variables of for<'a> for the function and the return type of that function. It is hard to describe in words, so let's jump right into the code:
use std::fs::File;
use std::io::{BufRead, BufReader, Result};
fn static_dispatcher<'b, I>(
tokenize: impl for<'a> Fn(&'a str) -> I,
ifs: BufReader<File>,
) -> Result<()>
where
I: Iterator<Item = &'b str>,
{
ifs.lines()
.map(|line| tokenize(&line.unwrap()).count())
.for_each(move |n| {
println!("{n}");
});
Ok(())
}
fn main() -> Result<()> {
let ifs = BufReader::new(File::open("/dev/stdin")?);
static_dispatcher(|line| line.split_whitespace(), ifs)
// static_dispatcher(|line| line.split('\t'), ifs)
}
The compiler complains that the lifetime relation of the tokenize's input 'a and output 'b is not specified.
--> src/main.rs:21:30
|
21 | static_dispatcher(|line| line.split_whitespace(), ifs)
| ----- ^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
| | |
| | return type of closure is SplitWhitespace<'2>
| has type `&'1 str`
|
= note: requirement occurs because of the type `SplitWhitespace<'_>`, which makes the generic argument `'_` invariant
= note: the struct `SplitWhitespace<'a>` is invariant over the parameter `'a`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
I want to specify 'a = 'b, but I can't because 'a comes from for<'a>, which is not visible for the type I.
I also tried
fn static_dispatcher<'a, I>(
tokenize: impl Fn(&'a str) -> I,
ifs: BufReader<File>,
) -> Result<()>
where
I: Iterator<Item = &'a str>,
but this does not work either b/c the lifetime of tokenize argument must be generic, i.e., must be used with for <'a>.
How can I fix this problem?

Closure arguments: passing a function that mutates the inner variables

The idea is to to have one closure (change_x in this case) that captures state (x in this case) that takes a function as its parameter(alterer) that would dictate how the inner state changes.
pub fn plus17(h: & u64) -> u64 {
*h + 17
}
pub fn main() {
let x = 0; //take x by reference
let mut change_x = move |alterer: &dyn FnOnce(&u64) ->u64 | alterer(&x) ;
change_x(&mut plus17);
println!("{}", x);
}
I can't seem to get the types right however:
error[E0161]: cannot move a value of type dyn for<'r> FnOnce(&'r u64) -> u64: the size of dyn for<'r> FnOnce(&'r u64) -> u64 cannot be statically determined
--> playground/src/main.rs:19:69
|
19 | let mut increment_x = move |alterer: &dyn FnOnce(&u64) ->u64 | alterer(&x) ;
| ^^^^^^^
error[E0507]: cannot move out of `*alterer` which is behind a shared reference
--> playground/src/main.rs:19:69
|
19 | let mut increment_x = move |alterer: &dyn FnOnce(&u64) ->u64 | alterer(&x) ;
| ^^^^^^^ move occurs because `*alterer` has type `dyn for<'r> FnOnce(&'r u64) -> u64`, which does not implement the `Copy` trait
I'm not sure if i'm justified in putting the dyn where i put it, it was a compiler's suggestion and im not really sure why i have to put it there. Is it because the alterer can be of arbitrary size despite the input/return type of &u64->u64?
I have also tried to make alterer a FnMut as opposed to FnOnce, but im also pretty shaky as to their distinction and the fact that a given alterer would run only once (at the moment of invocation by outer closure change_x) seemed reasonable.
FnOnce needs an owned self. Thus alterer cannot be FnOnce, because it is not owned but a reference.
You can either make it &dyn Fn or &mut dyn FnMut (I'd recommend going with FnMut), or take Box<dyn FnOnce>.

Chain iterators to references of different lifetimies

I want to build a recursive function for traversing a tree in Rust. The function should always get the next element and an iterator over references to the ancestor elements.
For the iterator over ancestor elements, one could in principle use the chain and once methods. Consider the following simple example, where the tree is jsut a Vec (for the purpose of this demonstration):
fn proceed<'a, I>(mut remaining: Vec<String>, ancestors: I)
where
I: Iterator<Item = &'a String> + Clone,
{
if let Some(next) = remaining.pop() {
let next_ancestors = ancestors.chain(std::iter::once(&next));
proceed(remaining, next_ancestors);
}
}
Playground
This fails to compile because &next has a shorter lifetime than 'a:
error[E0597]: `next` does not live long enough
--> src/lib.rs:6:62
|
1 | fn proceed<'a, I>(mut remaining: Vec<String>, ancestors: I)
| -- lifetime `'a` defined here
...
6 | let next_ancestors = ancestors.chain(std::iter::once(&next));
| --------------------------------^^^^^--
| | |
| | borrowed value does not live long enough
| argument requires that `next` is borrowed for `'a`
7 | proceed(remaining, next_ancestors);
8 | }
| - `next` dropped here while still borrowed
I tried to overcome this by adding an explicit second lifetime 'b: 'a and forcing an explicit reference by something like let next_ref: &'b String = &next, but that yields a (different) error message as well.
One solution I came up with was to call map as follows:
let next_ancestors = ancestors.map(|r| r).chain(std::iter::once(&next));
As pointed out by #trentcl, this doesn't actually solve the problem, as the compiler then gets stuck in an infinite loop when compiling proceed for all the nested Chains when one actually tries to call the function.
The pieces of solution are already around, just to summarize:
As you already know, using map(|r| r) "decouples" the lifetime requirement of ancestors
from the lifetime of &next.
As already stated in the comments, fixing
the infinite recursion is a matter to change ancestors into a trait object.
fn proceed<'a>(mut remaining: Vec<String>, ancestors: &mut dyn Iterator<Item = &'a String>) {
if let Some(next) = remaining.pop() {
let mut next_ancestors = ancestors.map(|r| r).chain(std::iter::once(&next));
proceed(remaining, &mut next_ancestors);
}
}
fn main() {
let v = vec!["a".to_string(), "b".to_string()];
proceed(v, &mut std::iter::empty());
}

Understanding lifetimes for parameterized structs in Rust

The following code
struct Cat<'a, T> {
coolness: &'a T,
}
complains saying
error[E0309]: the parameter type `T` may not live long enough
--> src/main.rs:2:5
|
1 | struct Cat<'a, T> {
| - help: consider adding an explicit lifetime bound `T: 'a`...
2 | coolness: &'a T,
| ^^^^^^^^^^^^^^^
|
note: ...so that the reference type `&'a T` does not outlive the data it points at
--> src/main.rs:2:5
|
2 | coolness: &'a T,
| ^^^^^^^^^^^^^^^
With an explicit lifetime bound, it compiles. When I instantiate the struct where T is an &i32 and despite each reference having a different lifetime, the code compiles. My understanding is that the compiler sees that the inner & outlives the outer &:
struct Cat<'a, T>
where
T: 'a,
{
coolness: &'a T,
}
fn main() {
let b = 10;
{
let c = &b;
{
let fluffy = Cat { coolness: &c };
}
}
}
Does Cat { coolness: &c } expand to Cat { coolness: &'a &'a i32 }? Does the inner reference also assume the same lifetime and so forth for more nested references?
Does Cat { coolness: &c } expand to Cat { coolness: &'a &'a i32 }?
Yes, the Cat ends up with a reference to a reference. This can be demonstrated by the following code compiling:
let fluffy = Cat { coolness: &c };
fn is_it_a_double_ref(_x: &Cat<&i32>) {}
is_it_a_double_ref(&fluffy);
However, the lifetime on each reference is not necessarily the same.
My understanding is that the compiler sees that the inner & outlives the outer &
That's right. And this is precisely where the T: 'a bound comes into play.
Lifetime bounds are a bit tricky to understand at first. They put restrictions on the references contained in T. For example, given the bound T: 'static, types that don't contain any references, or only contain 'static references, e.g. i32 and &'static str, satisfy the bound, while types that contain non-'static references, e.g. &'a i32, don't, because 'a: 'static is false. More generally, given the bound T: 'a, the type T satisfies the bound if, for every lifetime parameter 'x on T, 'x: 'a is true (types with no lifetime parameters trivially satisfy the bound).
Back to your code now. Let's give some names to these references. We'll say the type of coolness is &'fluffy &'c i32. 'c is the lifetime of the variable c and 'fluffy is the lifetime of the variable fluffy (counterintuitively, lifetimes encode the scope of a borrow, not the lifetime of the referent, although the compiler does check that the borrow doesn't extend beyond the referent's lifetime). That means the type of Fluffy is Cat<'fluffy, &'c i32>. Is it true that &'c i32: 'fluffy?
To check if &'c i32: 'fluffy is true, we need to check if 'c: 'fluffy is true. 'c: 'fluffy is true because the variable c goes out of scope after fluffy.

Linking the lifetimes of self and a reference in method

I have this piece of code:
#[derive(Debug)]
struct Foo<'a> {
x: &'a i32,
}
impl<'a> Foo<'a> {
fn set(&mut self, r: &'a i32) {
self.x = r;
}
}
fn main() {
let v = 5;
let w = 7;
let mut f = Foo { x: &v };
println!("f is {:?}", f);
f.set(&w);
println!("now f is {:?}", f);
}
My understanding is that in the first borrow of the value of v, the generic lifetime parameter 'a on the struct declaration is filled in with the lifetime of the value of v. This means that the resulting Foo object must not live longer than this 'a lifetime or that the value of v must live at least as long as the Foo object.
In the call to the method set, the lifetime parameter on the impl block is used and the lifetime of the value of w is filled in for 'a in the method signature. &mut self is assigned a different lifetime by the compiler, which is the lifetime of f (the Foo object). If I switched the order of the bindings of w and f in the main function, this would result in an error.
I wondered what would happen if I annotated the &mut self reference with the same lifetime parameter 'a as r in the set method:
impl<'a> Foo<'a> {
fn set(&'a mut self, r: &'a i32) {
self.x = r;
}
}
Which results in the following error:
error[E0502]: cannot borrow `f` as immutable because it is also borrowed as mutable
--> src/main.rs:21:31
|
19 | f.set(&w);
| - mutable borrow occurs here
20 |
21 | println!("now f is {:?}", f);
| ^ immutable borrow occurs here
22 | }
| - mutable borrow ends here
In contrast to the example above, f is still considered mutably borrowed by the time the second println! is called, so it cannot be borrowed simultaneously as immutable.
How did this come to be?
By not leaving off the lifetime annotation the compiler filled one in for me for &mut self in the first example. This happens by the rules of lifetime elision. However by explicitly setting it to 'a in the second example I linked the lifetimes of the value of f and the value of w.
Is f considered borrowed by itself somehow?
And if so, what is the scope of the borrow? Is it min(lifetime of f, lifetime of w) -> lifetime of f?
I assume I haven't fully understood the &mut self reference in the function call yet. I mean, the function returns, but f is still considered to be borrowed.
I am trying to fully understand lifetimes. I am primarily looking for corrective feedback on my understanding of the concepts. I am grateful for every bit of advice and further clarification.
In the call to the method set the lifetime parameter on the impl block is used and the lifetime of the value of w is filled in for 'a in the method signature.
No. The value of the lifetime parameter 'a is fixed at the creation of the Foo struct, and will never change as it is part of its type.
In your case, the compiler actually choses for 'a a value that is compatible with both the lifetimes of v and w. If that was not possible, it would fail, such as in this example:
fn main() {
let v = 5;
let mut f = Foo { x: &v };
println!("f is {:?}", f);
let w = 7;
f.set(&w);
println!("now f is {:?}", f);
}
which outputs:
error[E0597]: `w` does not live long enough
--> src/main.rs:21:1
|
18 | f.set(&w);
| - borrow occurs here
...
21 | }
| ^ `w` dropped here while still borrowed
|
= note: values in a scope are dropped in the opposite order they are created
Exactly because the 'a lifetime imposed by v is not compatible with the shorter lifetime of w.
In the second example, by forcing the lifetime of self to be 'a as well, you are tying the mutable borrow to the lifetime 'a as well, and thus the borrow ends when all items of lifetime 'a goes out of scope, namely v and w.

Resources