我正在研究一种以编程方式在内存中构造新结构并将其附加到链表的方法。
我正在做的方式是新建一个结构,新建一个指向它的盒子,然后用Option包裹它。然后,我需要将尾指针向下移动到新创建的指针。
我要上一个节点拥有下一个节点。所以尾指针必须 “借用”节点。
#[derive(Debug)]
struct S {
next: Option<Box<S>>,
}
#[cfg(test)]
mod test {
use crate::tmp::S;
use std::borrow::Borrow;
#[test]
fn test_tmp() {
let mut s1 = S { next: None };
let mut tail = &s1;
// potentially within a loop as a linked list has multiple nodes
{
let mut s2 = S { next: None };
s1.next = Some(Box::new(s2));
// tail = &s2;
tail = s1.next.as_ref().unwrap();
}
println!("s1: {:?}", &s1);
println!("tail: {:?}", &tail);
}
}
注释掉的行不起作用,因为所有者已移至s1,我很好。
tail = &s2
太丑陋了,但下一行有效。假设我有一个包裹得很深的结构,我想借用它。这是否意味着我必须再次对其进行深度包装?
tail = s1.next.as_ref().unwrap();
必须有一些更好的方法。有提示吗?
答案 0 :(得分:0)
是的,这是唯一的方法,但这一点也不坏。
当您将一个值推入一个链表时,您已经移动了该值的有效所有权(我说有效,因为只有Box
有效拥有该底层值,但并不直接拥有到最后一个节点。但是你是怎么做到的呢?要将A
移至B
,您还必须拥有&mut B
。而且您只想获得一个&A
(或一个&mut A
)。既然您已经借用了它,为什么不从&mut B
中得到它呢?
我不明白您所说的“深层包裹”的真正含义。但是假设我们有一个head: S
和一个tail: &mut S
,其中tail
借用了由head
领导的链表的最后一个节点。现在,要在将tail
移至new_tail
后获得tail
的更新参考,只需将tail
更改为tail.next
(加上Option
和Box
展开代码,但不会影响所有权。
看看这个新的游乐场代码:https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=1103d2f039c24ed6ea78408d613a4261
您应该使用tail: &mut S
而不是head
插入数据。这是链接列表的重点。因此,要回答您的问题,是的,您必须从其先例节点借用移动的节点,但是无论如何您都已借入了先例节点,所以这并不难看。
实际上,我在那儿作弊。我偷偷交换了最后两行println!
。如果将它们交换回去,您将意识到&s1
不能在最后一次使用tail
之前使用,因为tail
可变地(因此专门)借用了s1
中的内容。 / p>
error[E0502]: cannot borrow `s1` as immutable because it is also borrowed as mutable
那么如何解决这个问题?您不能直接执行此操作,因为如果线程在处理某些可变数据时出现紧急情况,则可能会导致数据中毒。 This question还讨论了为什么可变引用不能重用。
您可能想使用Cell
来保存要创建的数据internally mutable with just an immutable borrow。但这将是棘手的。或者,如果您想使用多线程,则可以尝试Mutex
。
但是除了所有这些复杂性之外,如果您想要真实,直观,快速,低级的Rust,则必须使用Unsafe Rust。