我正在尝试创建一个结构体实例链,如下所示:
Struct_instance_a:
id:1
prev:None
Struct_instance_b:
id:2
prev:Struct_instance_a
etc..
但是从编译器中得到这个错误:
error[E0382]: borrow of moved value: `a`
error[E0382]: borrow of moved value: `a`
--> src/main.rs:31:9
|
28 | let a = crate::Node::new(None, 1);
| - move occurs because `a` has type `Node`, which does not implement the `Copy` trait
29 | let b=crate::Node::new(Some(a), 2);
| - value moved here
30 |
31 | assert_eq!(a.id, b.prev.unwrap().id);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ value borrowed here after move
这是我的代码片段:
fn main() {
println!("hello");
}
pub struct Node {
prev: Option<Box<Node>>,
id: u64,
}
impl Node {
fn new(prev: Option<Node>, id:u64) -> Node {
Node {
prev: match prev {
None => None,
Some(prev) => Some(Box::new(prev))
},
id
}
}
}
#[cfg(test)]
mod tests {
#[test]
fn test_children() {
let a = crate::Node::new(None, 1);
let b = crate::Node::new(Some(a), 2);
assert_eq!(a.id, b.prev.unwrap().id);
}
}
我是 Rust 新手,试图理解为什么这不起作用。到目前为止,我已经阅读了有关所有权、借用和生命周期的内容,并尝试了这些内容的一些组合。感觉我已经接近解决方案,但还缺少一些基本知识。
当您执行
Node::new(some(a), 2)
时,a将不再可访问,它的所有权现在属于b
。
这就是为什么,当您稍后执行
a.id
时,它会显示 value borrowed here after move
,您将所有权移至 b
,因此您无法执行 a.id
。访问 a
的唯一方法是通过 b.prev.unwrap()
(这就是您所做的。
如果您希望节点
a
可以从 a
和 b.prev
访问,有很多方法可以做到这一点。
其中一种方法涉及根本不移动该值(因此
b
从一开始就不拥有 a
的所有权)。这可以通过参考来完成:
fn main() {
println!("hello");
}
pub struct Node<'inner_node> {
prev: Option<&'inner_node Node<'inner_node>>,
id: u64,
}
impl<'inner_node> Node<'inner_node> {
fn new<'a>(prev: Option<&'a Node<'a>>, id: u64) -> Node<'a> {
Node {
prev,
id
}
}
}
#[cfg(test)]
mod tests {
#[test]
fn test_children() {
let a = crate::Node::new(None, 1);
let b = crate::Node::new(Some(&a), 2);
assert_eq!(a.id, b.prev.unwrap().id);
}
}
这引入了生命周期注释,这可能不是您想要的。在这种情况下,您可以使用
RC
结构,它是一个智能指针,允许一个值拥有多个所有者,但需要进行一些运行时检查:
use std::rc::Rc;
fn main() {
println!("hello");
}
pub struct Node {
prev: Option<Rc<Node>>,
id: u64,
}
impl Node {
fn new(prev: Option<Rc<Node>>, id: u64) -> Node {
Node {
prev,
id
}
}
}
#[cfg(test)]
mod tests {
use std::rc::Rc;
#[test]
fn test_children() {
let a = Rc::new(crate::Node::new(None, 1));
let b = crate::Node::new(Some(a.clone()), 2);
assert_eq!(a.id, b.prev.unwrap().id);
}
}
请注意,为了实现这一点,我们正在做
a.clone()
。这会克隆 RC 指针,但不会克隆节点。所以现在存在 2 个指针(a
和 b.prev
),但只有 1 个(不包括 b
本身)节点。
RC 的缺点之一是现在里面的值是不可变的。如果您需要改变节点,它们必须是
Rc<RefCell<Node>>
而不是 Rc<Node>
。
RefCell
是另一个智能指针,就像Rc
一样。其中 Rc
允许一个值拥有多个所有者,RefCell
允许获取对内部对象的可变引用(通过运行时检查),即使 RefCell
本身不可变。通过组合 Rc
和 RefCell
,您可以拥有多个可以改变值的所有者。