1

我正在尝试为 Expat XML 解析器实现 Rust 包装器。我包装了 start_element 和 end_element 回调,它们在简单的情况下工作正常(例如,只计算 XML 元素)如下:

struct Expat {
  parser: expat::XML_Parser
}

type StartHandler = @fn(tag: &str, attrs: &[~str]);
type EndHandler = @fn(tag: &str);
type TextHandler = @fn(text: &str);

struct Handlers {
  start_handler: StartHandler,
  end_handler: EndHandler,
  text_handler: TextHandler
}

impl Expat {
  pub fn handlers(&self, start_handler: StartHandler, end_handler: EndHandler, text_handler: TextHandler) {
    let handlers = @Handlers {
      start_handler: start_handler,
      end_handler: end_handler,
      text_handler: text_handler
    };
    // How to do this properly?
    unsafe { cast::bump_box_refcount(handlers) };

    expat::XML_SetUserData(self.parser, unsafe { cast::transmute(&*handlers) });
}

我可以将简单的托管闭包传递给 handlers() 并让它们更新 @mut uint 值。

现在我想跨回调维护当前的 XPath 并且遇到问题:

let mut xpath: ~[~str] = ~[];
let xpath_start_handler: @fn(&str, &[~str]) = |tag: &str, _attrs: &[~str]| {
  vec::push(&xpath, tag.to_owned());
  println(fmt!("  start: %?", xpath));
};
let xpath_end_handler: @fn(&str) = |tag: &str| {
  println(fmt!("  end: %?", xpath));
  let top = vec::pop(&xpath);
  if top != tag.to_owned() {
    fail!(fmt!("expected end tag: %s, received end tag: %s", top, tag));
  }
};
let xpath_text_handler: @fn(&str) = |_text: &str| {
};
expat.handlers(xpath_start_handler, xpath_end_handler, xpath_text_handler);

编译器说唯一向量 xpath 已移入 xpath_start_handler 闭包,无法在 xpath_end_closure 中访问。

所以我的问题是在许多托管闭包中保持可变状态的最佳方法是什么?

4

1 回答 1

1

应该管理共享框,而不是唯一的:

let state: @mut ~[~str] = @mut ~[];
let push: @fn(~str) = |x| {
    vec::push(state, x);
};
let pop: @fn() -> ~str = || {
    vec::pop(state)
};
let count: @fn() -> uint = || {
    (&*state).len()
};
push(~"ho");
push(~"hey");
println(fmt!("%?", count()));
println(pop());
println(pop());
println(fmt!("%?", count()));

此外,可变唯一框的工作方式与可变托管框略有不同。

于 2013-05-24T04:56:39.950 回答