advance/circle-self-ref/circle-reference #757
Replies: 31 comments 18 replies
-
First Blood |
Beta Was this translation helpful? Give feedback.
-
要扎实这块的知识,还是要尝试手写简单的 链表和树结构的实现,不能光看不练。 |
Beta Was this translation helpful? Give feedback.
-
请问有没有大佬可以通过Option<Rc<RefCell>>来实现一个双向读的链表,目前在pre往回读的时候,没办法从里面读出数据,实在很难受,希望能有大佬可以给点思路 |
Beta Was this translation helpful? Give feedback.
-
仔细想想,Rc和Weak和js的引用计数机制以及WeakMap/WeakSet好像一模一样哈哈 |
Beta Was this translation helpful? Give feedback.
-
哪位大神解释一下? |
Beta Was this translation helpful? Give feedback.
-
为什么去掉 use std::rc::Rc;
fn main() {
let five = Rc::new(5);
let weak_five = Rc::downgrade(&five);
let strong_five = weak_five.upgrade();
println!("{:?}", strong_five);
drop(five);
let strong_five = weak_five.upgrade();
println!("{:?}", strong_five);
} |
Beta Was this translation helpful? Give feedback.
-
这里,List 为啥是 RefCell<Rc>,而不是 Rc<RefCell> 呢? |
Beta Was this translation helpful? Give feedback.
-
为啥第一个例子的一对多关系用Weak指针 但是第二个例子的一对多关系反而是 Weak指针应该在什么地方使用,是以关系决定,还是都可以?只要这种双向引用关系不出现循环引用就行了 |
Beta Was this translation helpful? Give feedback.
-
看起来rust这些特性是在为自己的设计填坑,实际使用价值有没有 |
Beta Was this translation helpful? Give feedback.
-
tree那个例子为什么用ReCell<Rc<>> 而不是 Rc<RefCell<>> |
Beta Was this translation helpful? Give feedback.
-
断断续续用时了一个月看到这一章, 在编译器的各种暴击之后,终于能够自己独立的写出链表和二叉树了。 快哭了都! |
Beta Was this translation helpful? Give feedback.
-
为什么 a.tail() 会导致循环调用呢?不就是一个match 函数吗? |
Beta Was this translation helpful? Give feedback.
-
parent没有了,是不是leaf也没了存在的必要? |
Beta Was this translation helpful? Give feedback.
-
只能说干得漂亮。 use std::cell::RefCell;
use std::rc::Rc;
#[derive(Debug)]
enum List<T> {
Elem(T, RefCell<Rc<List<T>>>),
None,
}
impl<T> List<T> {
fn new(t: T) -> Rc<Self> {
Rc::new(Self::Elem(t, RefCell::new(Rc::new(List::None))))
}
fn set_next(&self, list: &Rc<List<T>>) -> Option<&RefCell<Rc<List<T>>>> {
match self {
List::Elem(_, next) => {
*next.borrow_mut() = list.clone();
Some(next)
},
_ => None,
}
}
}
fn main() {
let a = List::new("a");
let b = List::new("b");
println!("a.count = {}, b.count = {}", Rc::strong_count(&a), Rc::strong_count(&b));
b.set_next(&a);
a.set_next(&b);
println!("a.count = {}, b.count = {}", Rc::strong_count(&a), Rc::strong_count(&b));
println!("a = {:?}", a);
} |
Beta Was this translation helpful? Give feedback.
-
尝试着用这章的知识写了一个tree,并实现广度优先编历。不知道有没有办法把迭代器改为使用引用,从weak.borrow里借用出来的是一个临时引用,我没办法在迭借器里持有它。 use std::cell::RefCell;
use std::collections::linked_list::LinkedList;
use std::fmt::Debug;
use std::rc::Rc;
use std::rc::Weak;
#[derive(Debug)]
struct Node<T: Debug> {
value: T,
parent: RefCell<Weak<Node<T>>>,
children: RefCell<Vec<Rc<Node<T>>>>,
}
#[derive(Debug)]
struct NodeIterator<T: Debug> {
nodes: LinkedList<Rc<Node<T>>>,
}
impl<T: Debug> Node<T> {
fn new(value: T) -> Rc<Self> {
Rc::new(
Self {
value,
parent: RefCell::new(Weak::new()),
children: RefCell::new(Vec::new()),
}
)
}
fn add_child(self: &Rc<Self>, child: Rc<Node<T>>) {
*child.parent.borrow_mut() = Rc::downgrade(self);
self.children.borrow_mut().push(child);
}
fn iter(self: &Rc<Self>) -> NodeIterator<T> {
let mut nodes = LinkedList::new();
nodes.push_front(self.clone());
NodeIterator { nodes }
}
}
impl<T: Debug> Drop for Node<T> {
fn drop(&mut self) {
while let Some(_node) = self.children.borrow_mut().pop() {}
}
}
impl<T: Debug> Iterator for NodeIterator<T> {
type Item = Rc<Node<T>>;
fn next(&mut self) -> Option<Self::Item> {
match self.nodes.pop_back() {
Some(node) => {
node.children
.borrow()
.iter()
.all(|node| {
self.nodes.push_front(node.clone());
true
});
Some(node)
},
_ => None,
}
}
}
fn main() {
let n1 = Node::new(1);
let n11 = Node::new(11);
n11.add_child(Node::new(111));
let n12 = Node::new(12);
let n121 = Node::new(121);
n121.add_child(Node::new(1211));
n12.add_child(n121);
n12.add_child(Node::new(122));
let n13 = Node::new(13);
n13.add_child(Node::new(131));
let n132 = Node::new(132);
n132.add_child(Node::new(1321));
n13.add_child(n132);
let n133 = Node::new(133);
n133.add_child(Node::new(1331));
n133.add_child(Node::new(1332));
n133.add_child(Node::new(1333));
n13.add_child(n133);
n1.add_child(n11);
n1.add_child(n12);
n1.add_child(n13);
println!("root = {:?}\r\n\r\n", n1);
for node in n1.iter() {
println!("node = {:?}", node.value);
}
} |
Beta Was this translation helpful? Give feedback.
-
为什么我把第11行的assert_eq语句注释掉了,最后strong_five还是Some(5) use std::rc::Rc;
} |
Beta Was this translation helpful? Give feedback.
-
''' let p: (&i32, i32) = (&5, 0); 虽然在IDE中会告诉我答案,但是具体怎么发生的希望有大佬总结一下 |
Beta Was this translation helpful? Give feedback.
-
还是objc |
Beta Was this translation helpful? Give feedback.
-
rc<refcell<>>可以实现赋值改变,refcell<rc<>>可以实现指向对象的改变。但是rust提供的指针功能没有可以同时改变这两者的,我只能说是坑不比cpp少到哪里去 |
Beta Was this translation helpful? Give feedback.
-
你好,您的邮件已收到,谢谢。
|
Beta Was this translation helpful? Give feedback.
-
你好,您的邮件已收到,谢谢。
|
Beta Was this translation helpful? Give feedback.
-
感觉C++工程化发展过程中踩过的坑, 各个标准的解决方案, Rust也避免不了. 这也说明理论,科学和工程的巨大鸿沟. 约学习Rust, 越觉得其像是C++ 23的一个"安全版子集". 学好Rust后, 不管使用Rust, C语言还是C++, 相信技能会大大增强, 心智负担会大大减小. Rust开发学习, 可以从娃娃抓起, 建议大学课程中可以引入Rust作为计算机学习语言,这样Rust开发人才问题会缓解一大部分.希望Rust能够为我们基础软件自主化创新贡献宝贵力量. |
Beta Was this translation helpful? Give feedback.
-
你好,您的邮件已收到,谢谢。
|
Beta Was this translation helpful? Give feedback.
-
你好,您的邮件已收到,谢谢。
|
Beta Was this translation helpful? Give feedback.
-
一层套一层,太恐怖了,完全感受不到Rust基础部分的优美...... 难道Rust写稍微复杂些的工程就注定这样吗? |
Beta Was this translation helpful? Give feedback.
-
你好,您的邮件已收到,谢谢。
|
Beta Was this translation helpful? Give feedback.
-
use std::rc::{Rc, Weak};
use std::cell::RefCell;
struct Node {
value: i32,
// Node 的父节点:弱引用,用 RefCell 包裹实现内部可变性
parent: RefCell<Weak<Node>>,
// Node 的子节点:强引用,用 RefCell 包裹实现内部可变性
children: RefCell<Vec<Rc<Node>>>,
}
impl Node {
// 关联函数:创建一个新的 Node 实例,并用 Rc 包裹
fn new(value: i32) -> Rc<Node> {
Rc::new(Node {
value,
parent: RefCell::new(Weak::new()), // 初始时没有父节点
children: RefCell::new(vec![]), // 初始时没有子节点
})
}
}
fn main() {
// 1. 创建根节点和子节点
let root_node = Node::new(1); // root_node (Rc<Node>) 强引用 Node { value: 1, ... }
let child_node = Node::new(2); // child_node (Rc<Node>) 强引用 Node { value: 2, ... }
// 2. 建立父子关系 (核心步骤)
// a. 父节点强引用子节点
// root_node.children 是 RefCell<Vec<Rc<Node>>>
// 调用 .borrow_mut() 获取 RefCell 内部的可变借用,才能修改 Vec
root_node.children.borrow_mut().push(Rc::clone(&child_node));
// 此时,Node { value: 2, ... } 的强引用计数为 2 (由 child_node 和 root_node.children 内部的 Rc 共同拥有)
// b. 子节点弱引用父节点
// child_node.parent 是 RefCell<Weak<Node>>
// 调用 .borrow_mut() 获取 RefCell 内部的可变借用,才能修改 Weak
// 然后用 Rc::downgrade() 将 root_node 的强引用降级为弱引用,赋值给 child_node 的 parent 字段
*child_node.parent.borrow_mut() = Rc::downgrade(&root_node);
// 此时,Node { value: 1, ... } 的强引用计数为 1 (只由 root_node 拥有)
// 弱引用计数为 1 (由 child_node.parent 内部的 Weak 拥有)
println!("Root node strong count: {}", Rc::strong_count(&root_node)); // 1
println!("Child node strong count: {}", Rc::strong_count(&child_node)); // 2
// 3. 验证弱引用是否有效 (在父节点还在时)
if let Some(parent) = child_node.parent.borrow().upgrade() {
println!("Child's parent exists: {}", parent.value); // 输出: Child's parent exists: 1
} else {
println!("Child's parent does not exist.");
}
// 4. 观察生命周期和清理 (核心)
println!("--- root_node 离开作用域之前 ---");
drop(child_node); // 手动 drop child_node。Node { value: 2, ... } 的强引用计数从 2 变为 1 (只剩 root_node.children 内部的 Rc)
println!("Strong count of root_node (after child_node is dropped): {}", Rc::strong_count(&root_node)); // 1
// 此时,Node { value: 2, ... } 仍然存活,因为它被 root_node.children 强引用着。
} // `root_node` 在这里离开作用域。
// `root_node` 被 drop,它的 strong_count 变为 0。
// 它会释放其拥有的 `Node { value: 1, ... }` 实例。
// 在释放 Node { value: 1, ... } 的过程中,会 drop 其 `children` 字段。
// `children` 字段的 `Vec<Rc<Node>>` 会被 drop,其中 `Rc<Node { value: 2, ... }>` 被 drop。
// Node { value: 2, ... } 的 strong_count 变为 0 (因为它之前是 2,现在 1个 Rc 被 drop 掉了)。
// 最终,Node { value: 2, ... } 也被释放。
// 内存被完全清理,没有循环引用导致的泄漏。 |
Beta Was this translation helpful? Give feedback.
-
你好,您的邮件已收到,谢谢。
|
Beta Was this translation helpful? Give feedback.
-
你好,您的邮件已收到,谢谢。
|
Beta Was this translation helpful? Give feedback.
-
贴一个双向链表的练习实现,边学编写,实现的感觉不是很优雅,突出一个菜😅😅,大佬们指点指点,没有成功实现的兄弟也可以参考参考 lib.rspub mod utils {
use std::{
cell::RefCell,
rc::{Rc, Weak},
};
#[derive(Debug)]
pub struct Node {
value: String,
next: Option<Rc<RefCell<Node>>>,
prev: Option<Weak<RefCell<Node>>>,
}
impl Node {
pub fn new(value: &str) -> Self {
Self {
value: value.to_string(),
next: None,
prev: None,
}
}
pub fn new_ref(value: &str) -> Rc<RefCell<Self>> {
Rc::new(RefCell::new(Self::new(value)))
}
pub fn next(&self) -> Option<Rc<RefCell<Node>>> {
self.next.clone()
}
pub fn prev(&self) -> Option<Weak<RefCell<Node>>> {
self.prev.clone()
}
pub fn set_next(&mut self, next_node: Rc<RefCell<Node>>) {
self.next = Some(next_node);
}
pub fn set_prev(&mut self, prev_node: Weak<RefCell<Node>>) {
self.prev = Some(prev_node);
}
pub fn value(&self) -> &str {
&self.value
}
}
#[derive(Debug)]
pub struct LinkList {
head: Option<Rc<RefCell<Node>>>,
tail: Option<Rc<RefCell<Node>>>,
size: u32,
}
impl LinkList {
pub fn new() -> LinkList {
LinkList {
head: None,
tail: None,
size: 0,
}
}
pub fn push_back(&mut self, value: &str) {
let new_node = Node::new_ref(value);
self.size += 1;
// 判断tail是否为空,如果为空,则需要同时修改head与tail
if self.tail.is_none() {
self.head = Some(Rc::clone(&new_node));
self.tail = Some(Rc::clone(&new_node));
} else {
// 不为空,在尾部添加即可,并为尾部节点设置前向弱引用
self.tail
.as_ref()
.unwrap()
.borrow_mut()
.set_next(Rc::clone(&new_node));
new_node
.borrow_mut()
.set_prev(Rc::downgrade(&self.tail.as_ref().unwrap()));
// 移动 tail 指向新的尾部
self.tail = Some(new_node);
}
}
pub fn push_front(&mut self, value: &str) {
let new_node = Node::new_ref(value);
self.size += 1;
if self.head.is_none() {
// 空表
self.head = Some(Rc::clone(&new_node));
self.tail = Some(Rc::clone(&new_node));
} else {
// 不为空,在头部添加即可,并为头部节点设置后向弱引用
self.head
.as_ref()
.unwrap()
.borrow_mut()
.set_prev(Rc::downgrade(&new_node));
new_node
.borrow_mut()
.set_next(Rc::clone(&self.head.as_ref().unwrap()));
// 移动 head 指向新的头部
self.head = Some(new_node);
}
}
pub fn length(&self) -> u32 {
self.size
}
pub fn head(&self) -> Option<String> {
if self.head.is_none() {
None
} else {
Some(self.head.as_ref().unwrap().borrow().value().to_string())
}
}
pub fn tail(&self) -> Option<String> {
if self.tail.is_none() {
None
} else {
Some(self.tail.as_ref().unwrap().borrow().value().to_string())
}
}
pub fn iter(&self) -> ListIter {
ListIter::new(self)
}
pub fn revert_iter(&self) -> ListRevertIter {
ListRevertIter::new(self)
}
// 在指定位置删除元素
pub fn delete_at(&mut self, index: u32) {
// 找到对应的元素
for (iter_cursor, iter_item) in self.iter().enumerate() {
if iter_cursor == index as usize {
let prev_node = iter_item.as_ref().borrow().prev();
let next_node = iter_item.as_ref().borrow().next();
let has_next = !next_node.is_none();
let has_prev = match prev_node.clone() {
Some(weak_ref) => match Weak::upgrade(&weak_ref) {
Some(_) => true,
_ => false,
},
_ => false,
};
// 如果同时存在前级节点与后级节点:将前级节点的next指向后级节点,将后级节点的prev指向前级节点
if has_prev && has_next {
let prev_node = Weak::upgrade(&prev_node.unwrap()).unwrap();
let next_node = next_node.unwrap();
// 前级指向后级
prev_node.borrow_mut().set_next(Rc::clone(&next_node));
// 后级指向前级
next_node.borrow_mut().set_prev(Rc::downgrade(&prev_node));
self.size -= 1;
continue;
}
// 如果仅存在前级节点,不存在后级节点,将前级节点的next置空,移动list的tail指向
if has_prev && !has_next {
let prev_node = Weak::upgrade(&prev_node.unwrap()).unwrap();
prev_node.borrow_mut().next = None;
self.tail = Some(prev_node);
self.size -= 1;
continue;
}
// 如果仅存在后级节点,将当前节点的next置空即可
if !has_prev && has_next {
self.head = iter_item.borrow().next();
}
// 前后都不存在,当前链表就一个元素
if !has_next && !has_next {
self.head = None;
self.tail = None;
}
self.size -= 1;
}
}
}
// 在制定位置后插入元素
pub fn insert_at(&mut self, index: i32, node_val: &str) {
self.size += 1;
// 如果 Index < 0 则在表头插入
if index < 0 {
self.push_front(node_val);
return;
}
// 如果 Index >= length - 1 则在表尾插入
if index as u32 >= self.length() - 1 {
self.push_back(node_val);
return;
}
// 在指定元素后插入
for (iter_cursor, iter_item) in self.iter().enumerate() {
if iter_cursor == index as usize {
// 不需要判断目标元素后面是否还有元素,必然有的,没有的情况在上一个分支已经处理了
// 获取下一个节点
let next_node = iter_item.as_ref().borrow().next().unwrap();
let new_node = Node::new_ref(node_val);
// 新节点的后级节点指向新节点
next_node
.as_ref()
.borrow_mut()
.set_prev(Rc::downgrade(&new_node));
{
// 处理新节点自身的引用关系
let mut new_mut_ref = new_node.as_ref().borrow_mut();
new_mut_ref.set_next(next_node);
new_mut_ref.set_prev(Rc::downgrade(&iter_item));
}
// 新节点的前级节点指向新节点
iter_item.as_ref().borrow_mut().set_next(new_node);
}
}
}
}
pub struct ListIter {
current: Option<Rc<RefCell<Node>>>,
}
impl ListIter {
pub fn new(link_list: &LinkList) -> ListIter {
ListIter {
current: link_list.head.clone(),
}
}
}
impl Iterator for ListIter {
type Item = Rc<RefCell<Node>>;
fn next(&mut self) -> Option<Self::Item> {
if self.current.is_none() {
None
} else {
let node = self.current.take().unwrap();
self.current = node.borrow().next();
Some(node)
}
}
}
impl IntoIterator for LinkList {
type Item = Rc<RefCell<Node>>;
type IntoIter = ListIter;
fn into_iter(self) -> Self::IntoIter {
ListIter::new(&self)
}
}
// 为 &LinkList 实现 IntoIterator,这样可以多次迭代
impl<'a> IntoIterator for &'a LinkList {
type Item = Rc<RefCell<Node>>;
type IntoIter = ListIter;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
// 反向迭代器
pub struct ListRevertIter {
current: Option<Weak<RefCell<Node>>>,
}
impl ListRevertIter {
pub fn new(link_list: &LinkList) -> ListRevertIter {
if let Some(tail) = link_list.tail.clone() {
return ListRevertIter {
current: Some(Rc::downgrade(&tail)),
};
};
ListRevertIter { current: None }
}
}
impl Iterator for ListRevertIter {
type Item = Rc<RefCell<Node>>;
fn next(&mut self) -> Option<Self::Item> {
let val_opt = self.current.take();
if let Some(val) = val_opt {
if let Some(strong_val) = val.upgrade() {
// 修改当前迭代器指向的节点
let prev_node = strong_val.as_ref().borrow().prev();
self.current = prev_node;
return Some(strong_val);
}
}
None
}
}
} main.rsuse test_link_list::utils::*;
fn main() {
let mut link_list = LinkList::new();
link_list.push_front("我是第1个元素");
link_list.push_back("我是第2个元素");
link_list.push_back("我是第3个元素");
println!("head: {:?}", link_list.head());
println!("tail: {:?}", link_list.tail());
println!("size: {}", link_list.length());
link_list.insert_at(1, "我是插入的元素111");
link_list.insert_at(1, "我是插入的元素11");
link_list.insert_at(1, "我是插入的元素1");
for node in &link_list {
println!("正向迭代:{}", node.as_ref().borrow().value());
}
for node in link_list.revert_iter() {
println!("逆向迭代:{}", node.as_ref().borrow().value());
}
// 删除中间元素
link_list.delete_at(1);
// 删除表头元素
link_list.delete_at(0);
// 删除表尾元素
link_list.delete_at(link_list.length() - 1);
println!("{link_list:#?}");
} |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
advance/circle-self-ref/circle-reference
https://course.rs/advance/circle-self-ref/circle-reference.html
Beta Was this translation helpful? Give feedback.
All reactions