需求背景是解析html
一般有gc
的语言,我是这么写的:
func walk(node html.Node, nodeData NodeData) {
if nodeData == nil {
nodeData = new(NodeData)
}
if node.type == "div" {
walk(node, nodeData)//这里递归了
}
}
遍历完了以后,就得到了一个nodeData
数据
但是在Rust
里,这么弄行不通
fn walk(handle: &Handle, items: &mut Vec<Item>, item: Option<Item>) {
let node = handle;
match node.data {
NodeData::Document => println!("#Document"),
NodeData::Doctype {
ref name,
ref public_id,
ref system_id,
} => println!("<!DOCTYPE {} \"{}\" \"{}\">", name, public_id, system_id),
NodeData::Text { ref contents } => {
//println!("#text: {}", escape_default(&contents.borrow()))
println!("#text: {}", &contents.borrow())
},
NodeData::Comment { ref contents } => println!("<!-- {} -->", /*escape_default(contents)*/contents),
NodeData::Element {
ref name,
ref attrs,
..
} => {
print!("<{}", name.local);
for attr in attrs.borrow().iter() {
print!(" {}=\"{}\"", attr.name.local, attr.value);
}
println!(">");
},
NodeData::ProcessingInstruction { .. } => unreachable!(),
}
for child in node.children.borrow().iter() {
walk(child, items, item);//这里不行,因为move了
}
}
1
共 2 条评论, 1 页
评论区
写评论如果是sized类型的数据,不用管,直接传,因为会按位复制。 如果不是,有多线程则用arc,无多线程则用rc包一下,根据你的需求,用rc是可以的
提问尽量给一个能直接测试的代码啊。
这里是因为walk的item参数是传值的,下面的for循环有可能运行多次,那么第一次循环调用walk以后move掉了item,之后就没法再用了。
解决的方法有很多,最简单的是把walk里的item改成传引用的
item: &Option<Item>
,还可以用Rc什么的包一下,如果Item可以是copy的话实现copy也能解决这个问题。