一生的迭代混乱

发布于 2025-01-26 04:14:17 字数 2089 浏览 3 评论 0 原文

我是Rust的新手,目前一直在关注学习Rust完全有太多的链接列表示例。在 itermut 节之前,一切对我来说都是有意义的。但是,当实施 itermut (以与教程不同的方式)时,我对Rust中的生命周期机制完全感到困惑。情况是,首先我只是定义要实现的堆栈:

pub struct List<T> {
    head: Link<T>,
}

type Link<T> = Option<Box<Node<T>>>;

struct Node<T> {
    elem: T,
    next: Link<T>,
}

确定然后尝试以下面的方式实现迭代器时:

pub struct IterMut<'a, T>{
    this: &'a mut Link<T>
}

impl<T> List<T> {
    pub fn iter_mut(&mut self) -> IterMut<T> {
        IterMut {
            this: &mut self.head
        }
    }
}

impl<'a, T> Iterator for IterMut<'a, T>{
    type Item = &'a mut T;
    fn next(&mut self) -> Option<Self::Item> {
        if let Some(node) = self.this {
            Some(&mut node.elem)
        } else {
            None
        }
    }
}

它不会编译,结果说:

error: lifetime may not live long enough
impl<'a, T> Iterator for IterMut<'a, T>{
    -- lifetime `'a` defined here
    type Item = &'a mut T;
    fn next(&mut self) -> Option<Self::Item> {
            - let's call the lifetime of this reference `'1`
        if let Some(node) = self.this {
            Some(&mut node.elem)
            ^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'a`

最初,我实现功能 next Next < /code>以这种方式,使用 as_mut 地图

// function body in the fn next
self.this.as_mut().map(|node|{
    self.this = &mut node.next;
    &mut node.elem
})

这也触发了编译错误(不兼容的寿命)。

因此,我想知道这里发生了什么, self in fn Next 的生​​命周期与 itermut ('a)相同吗?对于这种情况有什么解决方法吗?

I am new to Rust and currently have been following Learning Rust With Entirely Too Many Linked Lists examples. Before section IterMut everything makes sense to me. Yet when implementing IterMut(in a differrnt way from the tutorial), I got totally confused by lifetime mechanism in Rust. Here is the case, first I'd just define the stack to be implemented:

pub struct List<T> {
    head: Link<T>,
}

type Link<T> = Option<Box<Node<T>>>;

struct Node<T> {
    elem: T,
    next: Link<T>,
}

Ok then when I try to implement iterator in the following way:

pub struct IterMut<'a, T>{
    this: &'a mut Link<T>
}

impl<T> List<T> {
    pub fn iter_mut(&mut self) -> IterMut<T> {
        IterMut {
            this: &mut self.head
        }
    }
}

impl<'a, T> Iterator for IterMut<'a, T>{
    type Item = &'a mut T;
    fn next(&mut self) -> Option<Self::Item> {
        if let Some(node) = self.this {
            Some(&mut node.elem)
        } else {
            None
        }
    }
}

It won't compile, the result says:

error: lifetime may not live long enough
impl<'a, T> Iterator for IterMut<'a, T>{
    -- lifetime `'a` defined here
    type Item = &'a mut T;
    fn next(&mut self) -> Option<Self::Item> {
            - let's call the lifetime of this reference `'1`
        if let Some(node) = self.this {
            Some(&mut node.elem)
            ^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'a`

Originally, I implement function next in this way, using as_mut and map:

// function body in the fn next
self.this.as_mut().map(|node|{
    self.this = &mut node.next;
    &mut node.elem
})

This also triggers compilation error (incompatible lifetime).

Therefore I wonder what is going on here, shouldn't self in fn next have the same lifetime as IterMut ('a)? And is there any workaround for this situation?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

离笑几人歌 2025-02-02 04:14:17

主要问题在于试图参考整个 head 。当该参考文献寿命时,您不能分发对其中任何东西的可变引用。不过,您只需要访问节点 head 中的。因此,首先,我们重构 itermut 仅将引用保留到任何给定的节点

pub struct IterMut<'a, T>{
    this: Option<&'a mut Node<T>>
}

现在,要将其从 head 中获取,我们使用便利方法 as_deref_mut() option 提供。它只是为我们提供了内部的任何内容(如果有的话):

impl<T> List<T> {
    pub fn iter_mut(&mut self) -> IterMut<'_, T> {
        IterMut {
            this: self.head.as_deref_mut(),
        }
    }
}

现在,'a 仅与该 node 息息相关,我们可以用它做我们想做的事,就像一样,请 in:

impl<'a, T> Iterator for IterMut<'a, T>{
    type Item = &'a mut T;
    fn next(&mut self) -> Option<Self::Item> {
        if let Some(node) = self.this.take() {
            self.this = node.next.as_deref_mut();
            Some(&mut node.elem)
        } else {
            None
        }
    }
}

我们可以使用简单的 MAP 调用:

impl<'a, T> Iterator for IterMut<'a, T>{
    type Item = &'a mut T;
    fn next(&mut self) -> Option<Self::Item> {
        self.this.take().map(|node| {
            self.this = node.next.as_deref_mut();
            &mut node.elem
        })
    }
}

The principal problem lies in trying to take a reference to the whole head. While that reference lives, you can't hand out mutable references to anything inside it. You only need access to the Node that's inside head, though. So first, we refactor IterMut to only keep a reference into any given Node:

pub struct IterMut<'a, T>{
    this: Option<&'a mut Node<T>>
}

Now, to get that out of the head we use the convenience method as_deref_mut() that Option provides. It just gives us a mutable reference to whatever was inside it (if anything):

impl<T> List<T> {
    pub fn iter_mut(&mut self) -> IterMut<'_, T> {
        IterMut {
            this: self.head.as_deref_mut(),
        }
    }
}

Now, 'a is only tied to that Node and we can do what we want with it, like takeing it:

impl<'a, T> Iterator for IterMut<'a, T>{
    type Item = &'a mut T;
    fn next(&mut self) -> Option<Self::Item> {
        if let Some(node) = self.this.take() {
            self.this = node.next.as_deref_mut();
            Some(&mut node.elem)
        } else {
            None
        }
    }
}

And we can simplify that with a simple map call:

impl<'a, T> Iterator for IterMut<'a, T>{
    type Item = &'a mut T;
    fn next(&mut self) -> Option<Self::Item> {
        self.this.take().map(|node| {
            self.this = node.next.as_deref_mut();
            &mut node.elem
        })
    }
}
孤檠 2025-02-02 04:14:17

1。复制错误msg的简单代码

,用&amp; self &amp; mut self 作为输入和&amp;'作为回报值,它不是迭代器,而是具有相同的效果。

#[derive(Debug)]
struct Foo<'a> {
    r_m_s: &'a mut String, // non-Copy
    r_i_s: &'a String, // Copy
}

impl<'a> Foo<'a> {
  fn test_return_ref_field(&self) -> &'a String {
    self.r_i_s // Copy, no lifetime problem
  }
  
  fn test_return_ref_mut_field(&mut self) -> &'a mut String {
    //self.r_m_s
    todo!()
  }
}

fn main() {
}

fn test_return_ref_field 是可以的,因为不变的参考为复制类型。

要重现错误消息,请更改 test_return_ref_mut_field 方法返回 self.r_m_s

fn test_return_ref_mut_field(&mut self) -> &'a mut String {
    self.r_m_s
}

,错误msg看起来像:

error: lifetime may not live long enough
  --> tt.rs:34:6
   |
26 | impl<'a> Foo<'a> {
   |      -- lifetime `'a` defined here
...
31 |   fn test_return_ref_mut_field(&mut self) -> &'a mut String {
   |                                - let's call the lifetime of this reference `'1`
...
34 |      self.r_m_s
   |      ^^^^^^^^^^ method was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`

error: aborting due to 1 previous error

根据错误msg, self.r_m_s self.r_m_s 与输入参数&amp; mut '相同,并且毫无疑问要短于'a

因为 self.r_m_s 是非复制类型,并且当引用后面时也无法部分移动(输入参数&amp; mut self ),因此其寿命与&amp; mut self 一样。

怎么样,如果 self.r_m_s 是一种复合类型,例如&amp;'mut选项&lt; string&gt; ,例如:

let Some(ref mut v) = self.r_m_s else {
   todo!()
};
v

v 的类型是&amp; mut string ,似乎与 self.r_m_s 无关,但是其推断的寿命与 self.r_m_s 相同,我们将遇到同样的错误。这与问题的下一个相同。

让我们使用以下示例对其进行验证:

#[derive(Debug)]
struct F<'a> {
    r: &'a mut Option<String>,
}

fn main() {
    let mut s = "option string".to_string();
    let mut o_str = Some(s);

    let mut f = F {
        r: &mut o_str,
    };

    // create a mutable reference, same as `&mut self`
    let as_mut_ref_self = &mut f;

    let Some(v) = as_mut_ref_self.r else {
       return; 
    };

    v.push_str(" changed by v");

    // create a imutable reference
    // to end the lifetime of as_mut_ref_self
    let as_ref_self = &f;

    // !!! let's check how about the lifetime of v ?
    // !!! uncomment below line will cause error,
    // !!! now we know:
    // !!! the lifetime of v is tied to the as_mut_ref_self
    // println!("{:?}", v);

    println!("{:?}", as_ref_self);
}

2。不安全的修复

现在问题是返回值的寿命不等于或更长的时间或更长的寿命'a 。由于我们知道&amp; mut string 应该在生命周期内有效'a 让我们尝试与&amp; mut self 的寿命相结合。 /代码>直接

2.1一次尝试

更改 test_return_ref_mut_field 方法如下:

fn test_return_ref_mut_field(&mut self) -> &'a mut String { 
    let t: &'static mut String = unsafe {&mut *(self.r_m_s as *mut String)};
    t
}

上面的代码转换 mut *mut mut 原始指针,然后将原始指针转换回。

尽管它看起来像是本地变量 t 临时创建并返回的,但是RAW指针具有'static 寿命,但它比'a 更长明显地。

对于您的代码,您可以尝试使用此 UNSAFE 中转换 mut Node.elem in in some(&amp; mut node.elem)

**注意:此不安全的修复程序将具有多重mut引用问题,请尝试以下示例:**

#[derive(Debug)]
struct Foo<'a> {
    r_m_s: &'a mut String, // non-Copy type
    r_i_s: &'a String, // Copy type
}

impl<'a> Foo<'a> {
    fn test_return_ref_field(&self) -> &'a String {
        self.r_i_s
    }
  
    fn test_return_ref_mut_field(&mut self) -> &'a mut String {
        let t:&'static mut String = unsafe {&mut *(self.r_m_s as *mut String)};
        t
    }
}

fn main() {
    let mut mut_string = "mut string".to_string();
    let string = "imutable string".to_string();

    let mut f = Foo {
        r_m_s: &mut mut_string,
        r_i_s: &string,
    };

    let ref_mut_1 = f.test_return_ref_mut_field();
    let ref_mut_2 = f.test_return_ref_mut_field();
    let ref_mut_3 = f.test_return_ref_mut_field();

    ref_mut_1.push_str(" by ref_mut_1");
    ref_mut_2.push_str(" by ref_mut_2");
    ref_mut_3.push_str(" by ref_mut_3");
    
    println!("{:#?}", f);

    println!("ref_mut_1: {}\nref_mut_2: {}\nref_mut_3: {}", 
        ref_mut_1, ref_mut_2, ref_mut_3);
    
    println!("{:#?}", f);
}

但对于 itermut ,因为每次 next next 称为, self。此将更新到下一个节点,直到它到达 none 。两次都没有机会参考相同值。

2.2另一次尝试

代码,您还可以将 itermut 结构更改为:

pub struct IterMut<'a, T>{
    this: *mut Option<Box<Node<T>>>,
}

但是会导致错误,即'未使用,使用phantomdata保持它:

use std::marker::PhantomData;
pub struct IterMut<'a, T>{
    this: *mut Option<Box<Node<T>>>,
    phantom: PhantomData<&'a ()>,
}

<代码> fn iter_mut 应该更改为:

this: &mut self.head as *mut _,

并在 fn Next as中使用它:

let t = unsafe{ &mut *self.p }

2.3使用 option&lt;&lt;' &amp;'t

其他答案中已经提到的解决方案。

选项具有方便的采用方法,它是一个魔术函数实现,仔细使用不安全的代码,您可以将其视为官方解决方案,无法在安全下完成某些常见任务模式。

请看以下示例:

#[derive(Debug)]

struct F<'a> {
    r: Option<&'a mut String>,
}

fn main() {
    let mut s: String = "ssssss".to_string();
    let o_str: Option<&mut String> = Some(&mut s);

    // create a structure holder mutable reference to Option<String>
    let mut f: F<'_> = F {
        r: o_str,
    };

        
    // create a mutable reference
    let as_mut_ref_self = &mut f;
    
    // take the value of f.r by f,
    // and f.r will be replaced by None,
    let take = f.r.take();

    // v is &mut String
    let Some(v) = take else {
        return;
    };

    // to end the lifetime of as_mut_ref_self
    let as_ref_self = &f;

    // mutable reference droped already, 
    // now let's verify v is still valid.
    println!("{}", v);
}

1. simple codes to reproduce the error msg

Construct a function with &self or &mut self as input and &'a SOMETHING as return value, it's not an iterator but have the same effect.

#[derive(Debug)]
struct Foo<'a> {
    r_m_s: &'a mut String, // non-Copy
    r_i_s: &'a String, // Copy
}

impl<'a> Foo<'a> {
  fn test_return_ref_field(&self) -> &'a String {
    self.r_i_s // Copy, no lifetime problem
  }
  
  fn test_return_ref_mut_field(&mut self) -> &'a mut String {
    //self.r_m_s
    todo!()
  }
}

fn main() {
}

fn test_return_ref_field is Ok since immutable reference is Copy type.

To reproduce the error msg, change test_return_ref_mut_field method to return self.r_m_s

fn test_return_ref_mut_field(&mut self) -> &'a mut String {
    self.r_m_s
}

And the error msg looks like:

error: lifetime may not live long enough
  --> tt.rs:34:6
   |
26 | impl<'a> Foo<'a> {
   |      -- lifetime `'a` defined here
...
31 |   fn test_return_ref_mut_field(&mut self) -> &'a mut String {
   |                                - let's call the lifetime of this reference `'1`
...
34 |      self.r_m_s
   |      ^^^^^^^^^^ method was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`

error: aborting due to 1 previous error

According to error msg, the lifetime of self.r_m_s is same as input argument &mut self' and no doubt shorter than 'a.

Because self.r_m_s is non-Copy type, and it also can not be partially moved out when behind a reference (the input argument &mut self), so its lifetime is as same as &mut self.

How about if self.r_m_s is a compound type such as &'a mut Option<String>, for example:

let Some(ref mut v) = self.r_m_s else {
   todo!()
};
v

The type of v is &mut String, and seems nothing related to self.r_m_s, but its inferred lifetime is same as self.r_m_s, we will encounter the same error. And this is the same situation as fn next of the question.

Let's verify it using below example:

#[derive(Debug)]
struct F<'a> {
    r: &'a mut Option<String>,
}

fn main() {
    let mut s = "option string".to_string();
    let mut o_str = Some(s);

    let mut f = F {
        r: &mut o_str,
    };

    // create a mutable reference, same as `&mut self`
    let as_mut_ref_self = &mut f;

    let Some(v) = as_mut_ref_self.r else {
       return; 
    };

    v.push_str(" changed by v");

    // create a imutable reference
    // to end the lifetime of as_mut_ref_self
    let as_ref_self = &f;

    // !!! let's check how about the lifetime of v ?
    // !!! uncomment below line will cause error,
    // !!! now we know:
    // !!! the lifetime of v is tied to the as_mut_ref_self
    // println!("{:?}", v);

    println!("{:?}", as_ref_self);
}

2. unsafe fix

Now the problem is lifetime of return value is not equal to or longer than required lifetime 'a. Since we know &mut String should be valid within lifetime 'a, Let's try to cut its ties with the lifetime of &mut self directly.

2.1 one try

Change test_return_ref_mut_field method as below:

fn test_return_ref_mut_field(&mut self) -> &'a mut String { 
    let t: &'static mut String = unsafe {&mut *(self.r_m_s as *mut String)};
    t
}

Above codes convert &mut to *mut raw pointer then convert the raw pointer back.

Although it looks like a local variable t created temporarily and returned, but raw pointer have a 'static life time, it is longer than 'a obviously.

For your code, you can try this unsafe way to convert &mut node.elem in Some(&mut node.elem).

**Note: this unsafe fix will have multiple mut reference issue, please try below example: **

#[derive(Debug)]
struct Foo<'a> {
    r_m_s: &'a mut String, // non-Copy type
    r_i_s: &'a String, // Copy type
}

impl<'a> Foo<'a> {
    fn test_return_ref_field(&self) -> &'a String {
        self.r_i_s
    }
  
    fn test_return_ref_mut_field(&mut self) -> &'a mut String {
        let t:&'static mut String = unsafe {&mut *(self.r_m_s as *mut String)};
        t
    }
}

fn main() {
    let mut mut_string = "mut string".to_string();
    let string = "imutable string".to_string();

    let mut f = Foo {
        r_m_s: &mut mut_string,
        r_i_s: &string,
    };

    let ref_mut_1 = f.test_return_ref_mut_field();
    let ref_mut_2 = f.test_return_ref_mut_field();
    let ref_mut_3 = f.test_return_ref_mut_field();

    ref_mut_1.push_str(" by ref_mut_1");
    ref_mut_2.push_str(" by ref_mut_2");
    ref_mut_3.push_str(" by ref_mut_3");
    
    println!("{:#?}", f);

    println!("ref_mut_1: {}\nref_mut_2: {}\nref_mut_3: {}", 
        ref_mut_1, ref_mut_2, ref_mut_3);
    
    println!("{:#?}", f);
}

But for IterMut, since each time next called, self.this will be updated to point to next node until it reach None. there is no chance to mutable reference to same value twice.

2.2 another try

For your codes, you can also change IterMut structure to:

pub struct IterMut<'a, T>{
    this: *mut Option<Box<Node<T>>>,
}

But it will result to an error that 'a not used, use a phantomdata to hold it:

use std::marker::PhantomData;
pub struct IterMut<'a, T>{
    this: *mut Option<Box<Node<T>>>,
    phantom: PhantomData<&'a ()>,
}

fn iter_mut should change to:

this: &mut self.head as *mut _,

and use it in fn next as:

let t = unsafe{ &mut *self.p }

2.3 use Option<&'a mut T> instead of &'a mut T

This solution already mentioned in other answers.

Option has a convenient take method, it is a magic function implement with unsafe codes carefully and you can treat it as a official workaround for some common tasks can not be done under safe mode.

Have a look at below example:

#[derive(Debug)]

struct F<'a> {
    r: Option<&'a mut String>,
}

fn main() {
    let mut s: String = "ssssss".to_string();
    let o_str: Option<&mut String> = Some(&mut s);

    // create a structure holder mutable reference to Option<String>
    let mut f: F<'_> = F {
        r: o_str,
    };

        
    // create a mutable reference
    let as_mut_ref_self = &mut f;
    
    // take the value of f.r by f,
    // and f.r will be replaced by None,
    let take = f.r.take();

    // v is &mut String
    let Some(v) = take else {
        return;
    };

    // to end the lifetime of as_mut_ref_self
    let as_ref_self = &f;

    // mutable reference droped already, 
    // now let's verify v is still valid.
    println!("{}", v);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文