我正在使用Rust中的AST,而且我认为一件事情是整齐的,如果所有节点都可以简单地将切片包含在原始源字符串中,而不是复制内存。但是,我无法解释如何构建代码中的生命周期,以实现此目标。我天真的尝试产生了这个程序:
#[derive(Debug)]
struct Node<'source> {
slice : &'source str,
nid : usize ,
parent : usize ,
children: Vec<usize> ,
}
#[derive(Debug)]
struct Tree<'source> {
source: String ,
nodes : Vec<Node<'source>>,
}
impl<'source> Tree<'source> {
fn new() -> Self {
Tree {source: String::from("Hello World"), nodes: vec![]}
}
fn slice(&'source mut self, from: usize, to: usize) {
let new_nid = self.nodes.len();
self.nodes.push(
Node { slice: &self.source[from..to], nid: new_nid, parent: 0, children: vec![] }
);
}
}
fn main() {
let mut tree = Tree::new();
tree.slice(2, 6);
println!("{:?}", tree);
}
编译器输出:
error[E0502]: cannot borrow `tree` as immutable because it is also borrowed as mutable
--> ast.rs:32:22
|
31 | tree.slice(2, 6);
| ---- mutable borrow occurs here
32 | println!("{:?}", tree);
| ^^^^ immutable borrow occurs here
33 | }
| - mutable borrow ends here
这不能编译,因为:
节点包含的切片需要比slice()
函数调用更长久
因此,self
对slice()
采取的可变引用需要比slice()
函数调用更长。
因此,在tree
函数tree.slice()
调用后,main
仍然可以借用println!
。
因此,slice()
宏无法编译。
理想情况下,节点内的切片需要能够比self
调用更长,但可变参考self
不应该。我理解借用检查器是禁止的,因为source
包含切片引用的self
字符串。
考虑到这一点,我如何重构我的代码以允许节点将切片包含到源中,而不必借用slice
超过unsafe
函数的长度?这是否可行,或者我需要求助import Data.Char (digitToInt)
expand :: String -> [(Char, Int)]
expand (x:x':xs) = (x, digitToInt x'):expand xs
expand _ = []
?
答案 0 :(得分:1)
解决您问题的最简单方法是存储std::ops::Range<usize>
而不是&str
。然后,当您需要查看实际字符串时,在AST上提供一个方法,该方法需要Range<usize>
并返回&str
。
另一种方法是不拥有原始字符串,而是将AST与其解析字符串的生命周期联系起来,例如,
#[derive(Debug)]
struct Tree<'source> {
source: &'source str,
nodes : Vec<Node<'source>>,
}
你无法按照设置的方式进行操作,因为Rust不知道如何检查兄弟借用。如果你四处寻找兄弟借款问题,那么你将获得更多的背景。
来源:reddit post