< 返回版块

songday 发表于 2020-05-08 16:51

需求背景是解析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了
    }
}

评论区

写评论
reison1218 2020-05-09 01:15

如果是sized类型的数据,不用管,直接传,因为会按位复制。 如果不是,有多线程则用arc,无多线程则用rc包一下,根据你的需求,用rc是可以的

whfuyn 2020-05-08 17:39

提问尽量给一个能直接测试的代码啊。

use std::cell::RefCell;

struct Handle {
    data: Option<u32>,
    children: RefCell<Vec<Handle>>,
}

struct Item;


fn walk(handle: &Handle, items: &mut Vec<Item>, item: Option<Item>) {
    let node = handle;
    match node.data {
        Some(_) => println!("Some"),
        None => println!("None"),
    }
    for child in node.children.borrow().iter() {
        walk(child, items, item);//这里不行,因为move了
    }
}

fn main() {

}

这里是因为walk的item参数是传值的,下面的for循环有可能运行多次,那么第一次循环调用walk以后move掉了item,之后就没法再用了。

解决的方法有很多,最简单的是把walk里的item改成传引用的item: &Option<Item>,还可以用Rc什么的包一下,如果Item可以是copy的话实现copy也能解决这个问题。

1 共 2 条评论, 1 页