I want to implement a mutable Iterator for my custom struct as following:
#[derive(Debug, Clone)]
pub struct Message<'a> {
content: &'a str,
}
#[derive(Debug, Clone)]
pub struct Messages<'a> {
data: Vec<Message<'a>>
}
impl<'a> Messages<'a> {
// explicit lifetime 'a is required here for `&mut self`
// to disallow the invariance
pub fn iter_mut(&'a mut self) -> IterMut {
let messages = self.data.as_mut_slice();
IterMut { messages }
}
}
struct IterMut<'a> {
// store a slice of `Message` items to allow returning
// a mutable reference to particular Message in `next`
messages: &'a mut [Message<'a>],
}
impl<'a> Iterator for IterMut<'a> {
type Item = &'a mut Message<'a>;
fn next(&mut self) -> Option<Self::Item> {
let messages = &mut self.messages;
let messages = mem::replace(messages, &mut []);
let (elem, rest) = messages.split_first_mut()?;
self.messages = rest;
Some(elem)
}
}
When testing the code above, I've faced with a problem: when IterMut
is obtained once via iter_mut
call on some Messages
instance, this instance will be mutably borrowed until the end of the scope:
#[test]
fn test_iter_mut() {
let mut messages = Messages {
data: vec![
Message { content: "A" },
Message { content: "B" },
]
};
for msg in messages.iter_mut() {
*msg = Message { content: "C" }
}
// error[E0502]: cannot borrow `messages` as immutable because it is also borrowed as mutable
println!("Tasks: {:?}", messages);
}
Generally, it looks like the problem is I use the same 'a
lifetime everywhere, but an attempt to solve it by entering 2nd 'b
lifetime and using it as:
struct IterMut<'a, 'b> {
messages: &'b mut [Message<'a>],
}
impl<'a, 'b> Iterator for IterMut<'a, 'b> {
type Item = &'b mut Message<'a>;
...
}
did not succeed: the Compiler error is the same as previously ("swapping" 'a and 'b lifetimes doesn't work as well)
NOTE: i know that if I would use struct Message {content: String}
instead of struct Message<'a> {content: &'a str}
there will be no the same problem with lifetimes, but it's interesting for me how to solve it in current form.
Will be very pleasant for help!
I want to implement a mutable Iterator for my custom struct as following:
#[derive(Debug, Clone)]
pub struct Message<'a> {
content: &'a str,
}
#[derive(Debug, Clone)]
pub struct Messages<'a> {
data: Vec<Message<'a>>
}
impl<'a> Messages<'a> {
// explicit lifetime 'a is required here for `&mut self`
// to disallow the invariance
pub fn iter_mut(&'a mut self) -> IterMut {
let messages = self.data.as_mut_slice();
IterMut { messages }
}
}
struct IterMut<'a> {
// store a slice of `Message` items to allow returning
// a mutable reference to particular Message in `next`
messages: &'a mut [Message<'a>],
}
impl<'a> Iterator for IterMut<'a> {
type Item = &'a mut Message<'a>;
fn next(&mut self) -> Option<Self::Item> {
let messages = &mut self.messages;
let messages = mem::replace(messages, &mut []);
let (elem, rest) = messages.split_first_mut()?;
self.messages = rest;
Some(elem)
}
}
When testing the code above, I've faced with a problem: when IterMut
is obtained once via iter_mut
call on some Messages
instance, this instance will be mutably borrowed until the end of the scope:
#[test]
fn test_iter_mut() {
let mut messages = Messages {
data: vec![
Message { content: "A" },
Message { content: "B" },
]
};
for msg in messages.iter_mut() {
*msg = Message { content: "C" }
}
// error[E0502]: cannot borrow `messages` as immutable because it is also borrowed as mutable
println!("Tasks: {:?}", messages);
}
Generally, it looks like the problem is I use the same 'a
lifetime everywhere, but an attempt to solve it by entering 2nd 'b
lifetime and using it as:
struct IterMut<'a, 'b> {
messages: &'b mut [Message<'a>],
}
impl<'a, 'b> Iterator for IterMut<'a, 'b> {
type Item = &'b mut Message<'a>;
...
}
did not succeed: the Compiler error is the same as previously ("swapping" 'a and 'b lifetimes doesn't work as well)
NOTE: i know that if I would use struct Message {content: String}
instead of struct Message<'a> {content: &'a str}
there will be no the same problem with lifetimes, but it's interesting for me how to solve it in current form.
Will be very pleasant for help!
Share Improve this question asked Mar 11 at 8:46 AlexAlex 496 bronze badges1 Answer
Reset to default 4Generally, it looks like the problem is I use the same
'a
lifetime everywhere, but an attempt to solve it by entering 2nd'b
lifetime [...] did not succeed: the Compiler error is the same as previously ("swapping"'a
and'b
lifetimes doesn't work as well).
You are correct. The problem was that you used the same lifetime for the reference to the Vec
, and Message
's contents. To solve it you indeed need to introduce a second lifetime. I don't know why it didn't work for you. At the bottom of this answer I posted a working version, which was only modified by adding explicit second lifetime.
More intriguing question is: Why does your first snippet not work? The short answer is that you created &'a mut &'a
reference (modulo wrappers) which almost never is a correct thing and most of the time will lead to lifetime-related compiler errors.
The compiler's error isn't very good at pointing the reason of why you cannot borrow messages
as immutable while it is also borrowed as a mutable reference, but this is partly, because you have mislead the compiler.
By making iter_mut
signature as follows:
impl<'a> Messages<'a> {
// You elided the lifetime of IterMut here, but it is really: IterMut<'a>
pub fn iter_mut(&'a mut self) -> IterMut { ... }
}
you are telling compiler that when you call iter_mut
it assume that the lifetime of the message (&str
) is the same as the lifetime of the borrow of self
(Messages
). But in fact they are unrelated (to be strict there is a relation between them 'message: 'slice
, but it doesn't need to be expressed by any type constraints). So in your test, when you iterate over messages compiler sees that the lifetime of a Message
is 'static
, so it deduces that it must borrow messages
for 'static
as well. But that means, that you cannot borrow it ever again.
So the takeaway for this should be:
- never create
&'a mut &'a
(unless it actually is the correct thing) - if lifetimes don't need to be in a relation, make them separate
- do not elide lifetimes in returned types (your code violates
elided_named_lifetimes
lint)
#[derive(Debug, Clone)]
pub struct Message<'a> {
content: &'a str,
}
#[derive(Debug, Clone)]
pub struct Messages<'a> {
data: Vec<Message<'a>>
}
impl<'a> Messages<'a> {
// explicit lifetime 'a is required here for `&mut self`
// to disallow the invariance
pub fn iter_mut<'slice>(&'slice mut self) -> IterMut<'slice, 'a> {
let messages = self.data.as_mut_slice();
IterMut { messages }
}
}
pub struct IterMut<'slice, 'message> {
// store a slice of `Message` items to allow returning
// a mutable reference to particular Message in `next`
messages: &'slice mut [Message<'message>],
}
impl<'slice, 'message> Iterator for IterMut<'slice, 'message> {
type Item = &'slice mut Message<'message>;
fn next(&mut self) -> Option<Self::Item> {
let messages = &mut self.messages;
let messages = std::mem::replace(messages, &mut []);
let (elem, rest) = messages.split_first_mut()?;
self.messages = rest;
Some(elem)
}
}
#[test]
fn test_iter_mut() {
let mut messages = Messages {
data: vec![
Message { content: "A" },
Message { content: "B" },
]
};
for msg in messages.iter_mut() {
*msg = Message { content: "C" }
}
// error[E0502]: cannot borrow `messages` as immutable because it is also borrowed as mutable
println!("Tasks: {:?}", messages);
}
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744806418a4594801.html
评论列表(0条)