我试图了解如何使用内部可变性。这个问题与我之前的问题密切相关。
我有一个通用结构Port<T>
,它拥有一个Vec<T>
. 我们可以将端口 B“链接”到端口 A,因此,在读取端口 A 的内容时,我们可以读取端口 B 的内容。但是,这种链接对端口 A 的阅读器是隐藏的。这就是我实现该iter(&self)
方法的原因:
use std::rc::Rc;
pub struct Port<T> {
values: Vec<T>,
ports: Vec<Rc<Port<T>>>,
}
impl <T> Port<T> {
pub fn new() -> Self {
Self { values: vec![], ports: vec![] }
}
pub fn add_value(&mut self, value: T) {
self.values.push(value);
}
pub fn is_empty(&self) -> bool {
self.values.is_empty() && self.ports.is_empty()
}
pub fn chain_port(&mut self, port: Rc<Port<T>>) {
if !port.is_empty() {
self.ports.push(port)
}
}
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.values.iter().chain(
self.ports.iter()
.flat_map(|p| Box::new(p.iter()) as Box<dyn Iterator<Item = &T>>)
)
}
pub fn clear(&mut self) {
self.values.clear();
self.ports.clear();
}
}
该应用程序具有以下伪代码行为:
- 创建端口
- 环形:
- 用值填充端口
- 连锁港口
- 迭代端口的值
- 清除端口
该main
函数应如下所示:
fn main() {
let mut port_a = Rc::new(Port::new());
let mut port_b = Rc::new(Port::new());
loop {
port_a.add_value(1);
port_b.add_value(2);
port_a.chain_port(port_b.clone());
for val in port_a.iter() {
// read data
};
port_a.clear();
port_b.clear();
}
}
但是,编译器抱怨:
error[E0596]: cannot borrow data in an `Rc` as mutable
--> src/modeling/port.rs:46:9
|
46 | port_a.add_value(1);
| ^^^^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<Port<i32>>`
我一直在阅读几篇文章等,看来我需要合作Rc<RefCell<Port<T>>>
才能改变端口。我改变了实现Port<T>
:
use std::cell::RefCell;
use std::rc::Rc;
pub struct Port<T> {
values: Vec<T>,
ports: Vec<Rc<RefCell<Port<T>>>>,
}
impl<T> Port<T> {
// snip
pub fn chain_port(&mut self, port: Rc<RefCell<Port<T>>>) {
if !port.borrow().is_empty() {
self.ports.push(port)
}
}
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.values.iter().chain(
self.ports
.iter()
.flat_map(|p| Box::new(p.borrow().iter()) as Box<dyn Iterator<Item = &T>>),
)
}
// snip
}
这也不编译:
error[E0515]: cannot return value referencing temporary value
--> src/modeling/port.rs:35:31
|
35 | .flat_map(|p| Box::new(p.borrow().iter()) as Box<dyn Iterator<Item = &T>>),
| ^^^^^^^^^----------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| | |
| | temporary value created here
| returns a value referencing data owned by the current function
我想我知道问题出在哪里:p.borrow()
返回对被链接的端口的引用。我们使用该引用来创建迭代器,但是一旦函数完成,引用就会超出范围并且迭代器不再有效。
我不知道如何处理这个问题。我设法实现了以下不安全的方法:
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.values.iter().chain(self.ports.iter().flat_map(|p| {
Box::new(unsafe { (&*p.as_ref().as_ptr()).iter() }) as Box<dyn Iterator<Item = &T>>
}))
}
虽然这可行,但它使用了不安全的代码,并且必须有一个安全的解决方法。
我为我的应用程序的更多细节设置了一个游乐场。应用程序编译并输出预期的结果(但使用了不安全的代码)。