advance/circle-self-ref/circle-reference #757
Replies: 29 comments 17 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.
-
不知道我的理解对不对,所以使用weak可以防止出现循环引用并导致stack overflow的主要原因是 weak不会自动deref,所以他不会无限的被互相调用下去? |
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.
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