我正在开发一个(相当雄心勃勃的)文本编辑器,我试图实现任意垂直和水平拆分来显示文本缓冲区,如下所示:
buffer
-----------------
buffer |
-------| buffer
buffer |
我将此结构表示为二叉树类型的东西:
h
/ \
v b
/ \
b h
/ \
b b
其中v
是垂直拆分,h
是水平拆分,b
是缓冲区。
在代码表格中,就是这样:
pub enum LayoutNode {
Buf(Buffer),
Split(Box<Split>),
}
pub enum Split {
Vertical(LayoutNode, LayoutNode),
Horizontal(LayoutNode, LayoutNode)
}
pub struct Buffer {
content: String,
// more buffer-related stuff
}
一切都很好。我的垂直分割方法:
impl LayoutNode {
pub fn vertical_split(layout: LayoutNode) -> LayoutNode {
LayoutNode::Split(Box::new(Split::Vertical(layout, LayoutNode::Buf(Buffer::new()))))
// Buffer::new() returns an empty Buffer
}
}
此功能可编译,但不是整个故事。我有一个数据结构负责编辑器的布局节点,称为Editor
:
impl Editor {
pub fn new() -> Editor {
Editor {
buffers: LayoutNode::Buf(Buffer::empty()),
// more editor-related stuff
}
}
pub fn vertical_split(&mut self) {
// buffers needs to be a part of itself
self.buffers = LayoutNode::vertical_split(self.buffers);
// cannot move out of borrowed content ^
}
}
我已经看过mem::replace
,但我不确定这是否是我需要的嵌套数据结构。 rustc --explain
的{{1}}页面在这方面并非常有用。
在这种情况下,如何使用借阅检查器?我宁愿不克隆所有内容,因为每次拆分时,每个文件的新副本都会轻易浪费大量内存。
答案 0 :(得分:3)
mem::replace
通常在这种情况下用于在您生成新值时将字段设置为虚拟但有效的值。这是必要的,以确保如果线程在生成新值时发生混乱,析构函数将不会释放相同的对象两次。
在您的情况下,它可能看起来像这样:
impl Editor {
pub fn new() -> Editor {
Editor {
buffers: LayoutNode::Buf(Buffer::empty()),
}
}
pub fn vertical_split(&mut self) {
// buffers needs to be a part of itself
self.buffers = LayoutNode::vertical_split(
mem::replace(&mut self.buffers, LayoutNode::Buf(Buffer::empty())));
}
}
它的工作方式如下:mem::replace
接收对要替换的变量或字段的可变引用以及要分配的值,并返回旧值。您获得结果的所有权,因此您可以自由移动它。