在 Rust 中实现链表时如何复制原始指针? [英] How to copy a raw pointer when implementing a linked list in Rust?

查看:51
本文介绍了在 Rust 中实现链表时如何复制原始指针?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在 Rust 中编写递归类型 ListNode.我必须在结构中使用 Box 并且我正在尝试编写一个循环来添加 next ListNode.但是,我想尝试使用除递归方法之外的指针.

I am writing a recursive type ListNode in Rust. I have to use Box in the struct and I am trying to write a loop to add next ListNode. However, I would like to try using a pointer except recursive method.

#[derive(Debug)]
struct ListNode {
    val: i32,
    next: Option<Box<ListNode>>,
}

impl ListNode {
    fn new(i: i32) -> Self {
        ListNode { val: i, next: None }
    }

    fn add_l(&mut self, l: &Vec<i32>) {
        let mut p: *mut ListNode = self as *mut ListNode;
        for i in l {
            unsafe {
                (*p).next = Some(Box::new(ListNode::new(*i)));
                let temp_b = Box::from_raw(p);
                p = Box::into_raw(temp_b.next.wrap());
            };
        }
    }
}

fn main() {
    let mut a = ListNode::new(1);
    a.add_l(&vec![2, 3, 4, 5]);
    println!("{:?}", a);
}

我发现a被改成最后一个NodeListval为5:

I found that a is changed to the last NodeList with the val of 5:

ListNode { val: 5, next: None }

  1. 有什么方法可以复制一个指针来保持 a 的稳定?
  2. 如果我无法复制指针,我该如何实现?

推荐答案

首先:使用 unsafe 在这里完全没有必要,如果我看到我会说是恶意的它在任何真正的代码中.不要用 unsafe 来好玩".

First things first: using unsafe here is completely unnecessary and I would say actively malicious if I saw it in any real code. Don't use unsafe for "fun".

这是一个完全安全的函数实现,它向后构建要添加的新列表尾部:

Here's a completely safe implementation of the function which walks backwards to construct the new tail of the list to add:

fn add_l(&mut self, l: &[i32]) {
    let mut tail = None;

    for &val in l.iter().rev() {
        let next = tail.take();
        tail = Some(Box::new(ListNode { val, next }));
    }

    self.next = tail;
}

还有一个继续前进,但需要一个unwrap:

And one that goes forwards, but requires an unwrap:

fn add_l(&mut self, l: &[i32]) {
    let mut head = self;

    for &val in l {
        head.next = Some(Box::new(ListNode::new(val)));
        head = { head }.next.as_mut().unwrap();
    }
}

如果你不得不向前做并且不得不避免解包,那么也许你可以使用unsafe.每个 unsafe 块都应该包含大量注释,解释代码如何安全并且不会破坏您需要维护的保证.

If you had to do it in the forwards direction and had to avoid the unwrap, then maybe you could use unsafe. Every single unsafe block should contain a wealth of comments explaining how the code is safe and doesn't break the guarantees that you need to uphold.

fn add_l(&mut self, l: &[i32]) {
    let mut head = self;

    for &val in l {
        unsafe {
            // Boxing a value gives it a stable address.
            let mut node = Box::new(ListNode::new(val));

            // So long as this raw pointer doesn't escape this block, 
            // we don't need to worry about its lifetime as it should 
            // outlive what we need.
            let node_raw = &mut node as &mut ListNode as *mut ListNode;

            head.next = Some(node);

            // Now that we've moved the `Box` into its final place,
            // we throw away the reference to head to avoid mutable 
            // aliasing
            head = &mut *node_raw;
        }
    }
}

另见:

这篇关于在 Rust 中实现链表时如何复制原始指针?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆