Specify that lifetime of argument lasts for function call - rust

I have a trait with a function that takes a reference to an iterator:
#[derive(Clone)]
struct Dog {
name: &'static str,
}
trait DogListAction<'a, I>
where
I: Iterator<Item = &'a Dog>,
{
fn on_dog_list(&mut self, dog_list: I);
}
struct DogListActionExample {}
impl<'a, I> DogListAction<'a, I> for DogListActionExample
where
I: Iterator<Item = &'a Dog>,
{
fn on_dog_list(&mut self, dog_list: I) {
for dog in dog_list {
println!("{}", dog.name);
}
}
}
fn main() {
let dogs = vec![Dog { name: "Pluto" }, Dog { name: "Lilly" }];
let mut action_example = DogListActionExample {};
let mut dog_list_actions: Vec<Box<DogListAction<_>>> = vec![Box::new(action_example)];
loop {
let dog_clone = dogs.clone();
for dog_list_action in &mut dog_list_actions {
dog_list_action.on_dog_list(dog_clone.iter());
}
}
}
playground
It does not take any reference to the elements, so there is no need for it to last for more time than the function call.
Due to my limited understanding of lifetimes, I do not know yet how to express this. Calling this function causes a compilation error:
error[E0597]: `dog_clone` does not live long enough
--> src/main.rs:33:41
|
33 | dog_list_action.on_dog_list(dog_clone.iter());
| ^^^^^^^^^ borrowed value does not live long enough
34 | }
35 | }
| - `dog_clone` dropped here while still borrowed
36 | }
| - borrowed value needs to live until here
I guess the borrow checker thinks that data in dog_clone may be referenced after the function ends, but this is not the case.

The problem here is that the code can potentially save short-lived references to dog_clone elements in the longer-lived dog_list_actions. We need to tell the compiler that we will not be saving references the iterator produces. It can be done like this:
trait DogListAction {
fn on_dog_list<'a, I>(&'a mut self, dog_list: I)
where
I: Iterator<Item = &'a Dog>;
}
Now Item's can live for the duration of on_dog_list call. In the original code they must live for longer duration.
But this code creates another problem: we can't box the trait DogListAction anymore as it includes generic function. The usual approach here is to use a trait object:
trait DogListAction {
fn on_dog_list<'a>(&'a mut self, dog_list: Box<dyn Iterator<Item = &'a Dog> + 'a>);
}
Note the second 'a in Box<dyn Iterator<Item = &'a Dog> + 'a>. Rust adds a 'static trait bound to boxed trait objects by default and we don't want 'static here.
#[derive(Clone)]
struct Dog {
name: &'static str,
}
trait DogListAction {
fn on_dog_list<'a>(&'a mut self, dog_list: Box<dyn Iterator<Item = &'a Dog> + 'a>);
}
struct DogListActionExample {}
impl DogListAction for DogListActionExample {
fn on_dog_list<'a>(&'a mut self, dog_list: Box<dyn Iterator<Item = &'a Dog> + 'a>) {
for dog in dog_list {
println!("{}", dog.name);
}
}
}
fn main() {
let dogs = vec![Dog { name: "Pluto" }, Dog { name: "Lilly" }];
let action_example = DogListActionExample {};
let mut dog_list_actions: Vec<Box<DogListAction>> = vec![Box::new(action_example)];
{
let dogs_clone = dogs.clone();
for dog_list_action in &mut dog_list_actions {
dog_list_action.on_dog_list(Box::new(dogs_clone.iter()));
}
}
}
Playground

Related

Ensure that one lifetime outlives another in tree

I'm having a hard time figuring out the lifetime syntax that I need for the following code, which does not compile. The basic idea is that I'm creating an Abstract Syntax Tree, and each node must have a different type. Some node types must hold a reference to an external value. It's not possible to make this external value an owned type; it's actually a reference to disk file that must be shared by a number of nodes. Here's the code, as simple as I can make it:
trait Node {
fn init(&mut self, my_str: &str);
}
struct NodeParent {
pub children: Vec<Box<dyn Node>>,
}
impl Node for NodeParent {
fn init(&mut self, my_str: &str) {
for child in self.children.iter_mut() {
child.init(my_str);
}
}
}
struct NodeLeaf<'a> {
pub my_str: Option<&'a str>,
}
impl Node for NodeLeaf<'_> {
fn init(&mut self, my_str: &str) {
self.my_str = Some(my_str);
}
}
impl NodeLeaf<'_> {
pub fn new() -> Box<dyn Node> {
Box::new(NodeLeaf { my_str: None })
}
}
pub fn make_ast() {
let mut parent = NodeParent { children: vec![] };
let leaf = NodeLeaf::new();
parent.children.push(leaf);
let some_string = String::from("foo");
let my_str = some_string.as_str();
parent.init(my_str);
}
The error is:
error: lifetime may not live long enough
--> src/query/lifetime_test.rs:23:9
|
22 | fn init(&mut self, my_str: &str) {
| --------- - let's call the lifetime of this reference `'1`
| |
| has type `&mut NodeLeaf<'2>`
23 | self.my_str = Some(my_str);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2`
I know I need some kind of lifetime on &my_str everywhere it appears, but once I start taking the compiler's suggestion to start adding lifetimes here and there they proliferate, and I never get to code that compiles. I've also tried to Rc<>, but the code to make that work eludes me as well.
How do I specify that &my_str outlives the whole Node tree?
Link to the code on Rust Playground
Add a lifetime to Node:
trait Node<'a> {
fn init(&mut self, my_str: &'a str);
}
struct NodeParent<'a> {
pub children: Vec<Box<dyn Node<'a>>>,
}
impl<'a> Node<'a> for NodeParent<'a> {
fn init(&mut self, my_str: &'a str) {
for child in self.children.iter_mut() {
child.init(my_str);
}
}
}
struct NodeLeaf<'a> {
pub my_str: Option<&'a str>,
}
impl<'a> Node<'a> for NodeLeaf<'a> {
fn init(&mut self, my_str: &'a str) {
self.my_str = Some(my_str);
}
}
impl<'a> NodeLeaf<'a> {
pub fn new() -> Box<dyn Node<'a>> {
Box::new(NodeLeaf { my_str: None })
}
}
But this is not enough, because Box<dyn Node<'a>> is actually Box<dyn Node<'a> + 'static>, that is, it cannot contain any non-'static lifetime. You need to specify that it can contain lifetime 'a:
struct NodeParent<'a> {
pub children: Vec<Box<dyn Node<'a> + 'a>>,
}
impl<'a> NodeLeaf<'a> {
pub fn new() -> Box<dyn Node<'a> + 'a> {
Box::new(NodeLeaf { my_str: None })
}
}
Now you will get a different error:
error[E0597]: `some_string` does not live long enough
--> src/lib.rs:39:18
|
39 | let my_str = some_string.as_str();
| ^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
40 | parent.init(my_str);
41 | }
| -
| |
| `some_string` dropped here while still borrowed
| borrow might be used here, when `parent` is dropped and runs the destructor for type `NodeParent<'_>`
|
= note: values in a scope are dropped in the opposite order they are defined
Because Box<dyn Node> may have an arbitrary destructor, and it may access the stored string, we need to make sure it is still alive when the value is dropped. Do that by moving the string creation before the nodes:
pub fn make_ast() {
let some_string = String::from("foo");
let mut parent = NodeParent { children: vec![] };
let leaf = NodeLeaf::new();
parent.children.push(leaf);
let my_str = some_string.as_str();
parent.init(my_str);
}
Playground.

Why does an implementation of IntoIterator for a local type clash with the one in the core crate?

I am able to implement IntoIterator for a custom type, but when the IntoIterator is bound to a custom trait, I cannot implement that trait.
The code below shows the issue. When IntoIterator is implemented for a custom type (FakeReader), all works well. However, when I try to implement BmpReader for that type, the compiler seems to pick up the internal impl of IntoIterator and requires that my custom type be an Iterator.
use core::iter::Iterator;
/// The trait that I'm designing
pub trait BmpReader : IntoIterator {
const INTERNAL_BUFFER_SIZE: usize;
}
// Uncomment to see error
//impl BmpReader for FakeReader {
// const INTERNAL_BUFFER_SIZE: usize = 20;
//}
impl<'a> IntoIterator for &'a FakeReader {
type Item = &'a [u8];
type IntoIter = FakeReaderIterator<'a>;
fn into_iter(self) -> Self::IntoIter {
Self::IntoIter{
reader: &self,
index: 0,
}
}
}
struct FakeReader {
buffer: [u8; 20],
}
pub struct FakeReaderIterator<'a> {
reader: &'a FakeReader,
index: usize
}
impl<'a> Iterator for FakeReaderIterator<'a> {
type Item = &'a [u8];
fn next(&mut self) -> Option<Self::Item> {
if self.index == self.reader.buffer.len() {
return None;
}
let result = &self.reader.buffer[self.index..self.index+1];
self.index += 1;
Some(result)
}
}
fn main() {
let mut reader = FakeReader {
buffer: [0u8; 20]
};
let _= reader.buffer.iter_mut().enumerate().map(|(i,v)| *v = i as u8).count();
for i in &reader {
println!("{:?}", i)
}
}
Uncommenting the problematic impl block results in this error:
error[E0277]: `FakeReader` is not an iterator
--> src/main.rs:9:6
|
9 | impl BmpReader for FakeReader {
| ^^^^^^^^^ `FakeReader` is not an iterator
|
= help: the trait `Iterator` is not implemented for `FakeReader`
= help: the trait `IntoIterator` is implemented for `&'a FakeReader`
= note: required because of the requirements on the impl of `IntoIterator` for `FakeReader`
note: required by a bound in `BmpReader`
--> src/main.rs:4:23
|
4 | pub trait BmpReader : IntoIterator {
| ^^^^^^^^^^^^ required by this bound in `BmpReader`
playground link
When creating a trait with a trait bound, you are bounding Self to implement that trait, but in you case &FakeReader implement IntoIterator, so you can't implement BmpReader for FakeReader but you can for &FakeReader. You could write
impl<'a> BmpReader for &'a FakeReader {
const INTERNAL_BUFFER_SIZE: usize = 20;
}
Accessing the constant would mean to write
let size = <&FakeReader>::INTERNAL_BUFFER_SIZE;
and creating a fonction generic over BmpReader:
fn foo<T: BmpReader>(a: T) {
let _size = T::INTERNAL_BUFFER_SIZE;
let _iter = a.into_iter();
}
fn main() {
let reader = FakeReader {
buffer: [0u8; 20]
};
test(&reader);
}
The other solution is to bound &Self to implement IntoIterator for the trait:
pub trait BmpReader
where for <'a> &'a Self: IntoIterator
{
const INTERNAL_BUFFER_SIZE: usize;
}
impl BmpReader for FakeReader {
const INTERNAL_BUFFER_SIZE: usize = 20;
}
(the for<'a> &'a Self: IntoIterator is a suggestion of #Chayim Friedman)
you can now access the constant directly on FakeReader:
let size = FakeReader::INTERNAL_BUFFER_SIZE;
but creating a function generic over BmpReader needs you to specify the bound:
fn foo<T: BmpReader>(a: &T)
where for <'a> &'a T: IntoIterator
{
let _size = T::INTERNAL_BUFFER_SIZE;
let _iter = a.into_iter();
}
fn main() {
let reader = FakeReader {
buffer: [0u8; 20]
};
foo(&reader);
}
Bot solutions are valid, choose which one suits your needs the most and makes the code the most readable/maintenable.

How can I extend the lifetime of a temporary variable inside of an iterator adaptor in Rust?

I have a method make_iter() which creates an Iterator with multiple adapters in Rust, which can be simplified as the following MCVE:
fn make_iter(first: &First) -> Box<dyn Iterator<Item = String> + '_> {
Box::new(first.make_objects().flat_map(|second| {
second
.iter()
.filter(|third| third.as_str() != "t2")
.flat_map(|third| vec![format!("{}.A", third), format!("{}.B", third)].into_iter())
.chain(
vec![
format!("{}.A", second.name()),
format!("{}.B", second.name()),
]
.into_iter(),
)
}))
}
pub fn main() {
let first = First {};
for i in make_iter(&first) {
println!("{}", i);
}
}
struct First {}
impl First {
fn make_objects(&self) -> Box<dyn Iterator<Item = Second> + '_> {
Box::new(
vec![
Second::new("s1".to_string()),
Second::new("s2".to_string()),
Second::new("s3".to_string()),
]
.into_iter(),
)
}
}
struct Second {
name: String,
objects: Vec<String>,
}
impl Second {
fn new(name: String) -> Second {
Second {
name,
objects: vec!["t1".to_string(), "t2".to_string(), "t3".to_string()],
}
}
fn name(&self) -> &str {
&self.name
}
fn iter(&self) -> Box<dyn Iterator<Item = &String> + '_> {
Box::new(self.objects.iter())
}
}
Trying to compile this example yields a lifetime error:
error[E0597]: `second` does not live long enough
--> src/main.rs:3:9
|
3 | second
| ^^^^^^ borrowed value does not live long enough
...
14 | }))
| - `second` dropped here while still borrowed
This is understandable, as the second object is a temporary, and the iterator returned from the same closure attempts to borrow it, failing as second is dropped at the closure's end.
My objective would be to extend the lifetime of this object until the Iterator referencing it is dropped, but I don't know how.
Note that the structure implementations cannot be changed. Rust version is 1.34.2, edition 2018
extend the lifetime of this object
You cannot do this, period. It's simply not how things work.
See also:
Extend lifetime of variable
Extending borrowed lifetime for String slice
Is there any way to return a reference to a variable created in a function?
Here's a simpler reproduction:
use std::iter;
fn example(outer: impl Iterator<Item = Inner>) {
outer.flat_map(|i| i.iter().map(|v| v.clone()));
}
struct Inner;
impl Inner {
fn iter(&self) -> impl Iterator<Item = &()> + '_ {
iter::empty()
}
}
Since you have the restriction of being unable to change Inner, the easiest solution is to be more eager and proactively collect:
fn example(outer: impl Iterator<Item = Inner>) {
outer.flat_map(|i| i.iter().map(|v| v.clone()).collect::<Vec<_>>());
}
The only possibility I know of to avoid that would be to use a crate like rental or owning_ref.
See also:
Is there an owned version of String::chars?
How can I store a Chars iterator in the same struct as the String it is iterating on?
If you had the possibility of changing Inner, you should make a consuming iterator variant. Then the value does not need to live beyond the closure because the iterator has taken ownership.
use std::iter;
fn example(outer: impl Iterator<Item = Inner>) {
outer.flat_map(|i| i.into_iter().map(|v| v));
}
struct Inner;
impl Inner {
fn into_iter(self) -> impl Iterator<Item = ()> {
iter::empty()
}
}

Borrow checker error after adding generic parameter to struct

I have code that works, but it stops compiling with a borrow checker error after a change. I don't understand how the change could affect borrow checking.
Common part to both working and non-working code:
/// Some struct that has references inside
#[derive(Debug)]
struct MyValue<'a> {
number: &'a u32,
}
/// There are many structs similar to `MyValue` and there is a
/// trait common to them all that can create them. In this
/// example I use the `From` trait.
impl<'a> From<&'a u32> for MyValue<'a> {
fn from(value: &'a u32) -> Self {
MyValue { number: value }
}
}
/// `Producer` makes objects that hold references into it. So
/// the produced object must be first dropped before any new
/// one can be made.
trait Producer<'a, T: 'a> {
fn make(&'a mut self) -> T;
}
Here is the working code:
struct MyProducer {
number: u32,
}
impl MyProducer {
fn new() -> Self {
Self { number: 0 }
}
}
impl<'a, T: 'a + From<&'a u32>> Producer<'a, T> for MyProducer {
fn make(&'a mut self) -> T {
self.number += 1;
T::from(&self.number)
}
}
fn main() {
let mut producer = MyProducer::new();
println!(
"made this: {:?}",
<MyProducer as Producer<MyValue>>::make(&mut producer)
);
println!(
"made this: {:?}",
<MyProducer as Producer<MyValue>>::make(&mut producer)
);
}
This compiles and prints the expected output:
made this: MyValue { number: 1 }
made this: MyValue { number: 2 }
I don't like that MyProducer actually implements Producer for every T as it makes it impossible to call make directly on it. I would like to have a type that is a MyProducer for a specific T (for example for MyValue).
To achieve this, I want to add a generic parameter to MyProducer. Because the MyProducer does not really use the T, I use PhantomData to prevent the compiler from complaining.
Here is the code after changes:
use std::marker::PhantomData;
struct MyProducer<'a, T: 'a + From<&'a u32>> {
number: u32,
_phantom: PhantomData<&'a T>,
}
impl<'a, T: 'a + From<&'a u32>> MyProducer<'a, T> {
fn new() -> Self {
Self {
number: 0,
_phantom: PhantomData::default(),
}
}
}
impl<'a, T: From<&'a u32>> Producer<'a, T> for MyProducer<'a, T> {
fn make(&'a mut self) -> T {
self.number += 1;
T::from(&self.number)
}
}
fn main() {
let mut producer = MyProducer::<MyValue>::new();
println!("made this: {:?}", producer.make());
println!("made this: {:?}", producer.make());
}
The main function now looks exactly as I would like it to look like. But the code does not compile. This is the error:
error[E0499]: cannot borrow `producer` as mutable more than once at a time
--> src/main.rs:50:33
|
49 | println!("made this: {:?}", producer.make());
| -------- first mutable borrow occurs here
50 | println!("made this: {:?}", producer.make());
| ^^^^^^^^
| |
| second mutable borrow occurs here
| first borrow later used here
I don't understand why it no longer works. The produced object is still dropped before the next one is made.
If I call the make function just once, it compiles and works.
I am using edition 2018, so NLL is active.
Rust Playground: working version before change
Rust Playground: broken version after change
I reduced the noise from the code so the following is an even shorter version of the broken case which demonstrates the same problem: (test in the playground)
use std::marker::PhantomData;
#[derive(Debug)]
struct MyValue<'a>(&'a u32);
impl<'a> From<&'a u32> for MyValue<'a> {
fn from(value: &'a u32) -> Self {
MyValue(value)
}
}
struct MyProducer<'a, T>(u32, PhantomData<&'a T>);
impl<'a, T> MyProducer<'a, T>
where
T: From<&'a u32>,
{
fn new() -> Self {
Self(0, PhantomData)
}
fn make(&'a mut self) -> T {
self.0 += 1;
T::from(&self.0)
}
}
fn main() {
let mut producer = MyProducer::<MyValue>::new();
println!("made this: {:?}", producer.make());
println!("made this: {:?}", producer.make());
}
The main problem here is that the mutable borrow's lifetime is the lifetime of MyProducer, that is, the lifetime of the instance called producer is the same as the mutable borrow taken in its make method. Because the producer instance does not go out of scope (if it would then MyValue wouldn't be able to hold a reference to a value stored in it) so the mutable borrow lives until the end of main's scope. The first rule of borrowing is that there can only be a single mutable borrow of a given value in a scope at any time, hence the compiler error.
If you are looking at my solution here, which is actually working and does what I think you wanted it to: (test in the playground):
#[derive(Debug)]
struct MyValue<'a>(&'a u32);
impl<'a> From<&'a u32> for MyValue<'a> {
fn from(value: &'a u32) -> Self {
MyValue(value)
}
}
struct MyProducer(u32);
impl MyProducer {
fn new() -> Self {
Self(0)
}
fn make<'a, T>(&'a mut self) -> T
where
T: From<&'a u32>,
{
self.0 += 1;
T::from(&self.0)
}
}
fn main() {
let mut producer = MyProducer::new();
println!("made this: {:?}", producer.make::<MyValue>());
println!("made this: {:?}", producer.make::<MyValue>());
}
then you can see that the mutable borrow only lives as long as the make method, therefore after the invocation there's no more living mutable borrow to producer in main's scope, thus you can have another one.

How do I implement move semantics on a struct with a mutable field?

I have a minimal example of code that implements move semantics for some container:
use std::mem;
impl<'a, T: 'a + ?Sized> Drop for Cointainer<'a, T> {
fn drop(&mut self) {}
}
struct Cointainer<'a, T: 'a + ?Sized> {
item: &'a /* mut */ T,
}
impl<'a, T> Cointainer<'a, T> {
fn mv(self) -> Cointainer<'a, T> {
let new = Cointainer { item: /* &mut */ self.item };
mem::forget(self);
new
}
}
fn main() {}
That compiles and works without any problems.
I realized I will need to mutate the value referenced by Cointainer::item, so I've made the reference mut. When I do so, I get:
error[E0505]: cannot move out of `self` because it is borrowed
--> src/main.rs:14:21
|
13 | let new = Cointainer { item: /* &mut */ self.item };
| --------- borrow of `*self.item` occurs here
14 | mem::forget(self);
| ^^^^ move out of `self` occurs here
I need to create a new container and transfer ownership of item there, and drop the old one.
This example is artificial. The actual "move" operation does some other stuff, and doesn't necessarily return the same container type.
The rules of references state:
At any given time, you can have either but not both of:
One mutable reference.
Any number of immutable references.
Your code with immutable references works because those can be freely copied. Your code with mutable references fails because, as far as the compiler can tell, you would need to have have two concurrent mutable references: the saved reference in new and then mem::forget might also need it.
As humans, we recognize that mem::forget will not access the guts of our structure. This is what unsafe code is for: when the compiler cannot guarantee the code we have is truly safe.
A small unsafe block and some casting to a raw pointer and back solves the problem. As with any unsafe code, it should have a big comment block explaining why the compiler doesn't understand it and why it's truly safe.
impl<'a, T: 'a + ?Sized> Drop for Cointainer<'a, T> {
fn drop(&mut self) {
println!("dropping 1: {:p}", self.item)
}
}
struct Cointainer<'a, T: 'a + ?Sized> {
item: &'a mut T,
}
impl<'a, T> Cointainer<'a, T> {
fn into_inner(self) -> &'a mut T {
// I copied this code from Stack Overflow but didn't read
// the warning about explaining why it's safe. Sure hope
// this doesn't cause any bugs!
unsafe {
let x = self.item as *mut _;
std::mem::forget(self);
&mut *x
}
}
fn mv(self) -> Cointainer2<'a, T> {
let item = self.into_inner();
Cointainer2 { item }
}
}
struct Cointainer2<'a, T: 'a + ?Sized> {
item: &'a mut T,
}
impl<'a, T: 'a + ?Sized> Drop for Cointainer2<'a, T> {
fn drop(&mut self) {
println!("dropping 2: {:p}", self.item)
}
}
fn main() {
let mut a = String::new();
let c1 = Cointainer { item: &mut a };
let c2 = c1.mv();
}

Resources