2013-05-24 2 views
1

Я пытаюсь реализовать оболочку Rust для парсера Expat XML. Я завернул 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) }); 
} 

я могу передать простые управляемые затворов для обработчиков() и иметь их обновлять @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.

Итак, мой вопрос - это лучший способ поддерживать изменяемое состояние во многих управляемых замыканиях?

ответ

1

Shared коробка должна управляться, не уникальна:

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())); 

Кроме того, изменяемые уникальные коробки работают немного иначе, чем изменяемые управляемые коробки.

+0

Я сделал коробки для подсчета элементов XML, и это сработало нормально. Однако в этом случае vec :: push() абсолютно настаивает на изменяемом уникальном указателе. Нужно ли реализовать собственный вектор, который работает с управляемыми указателями? –

+0

Обновленный пример, чтобы решить вашу конкретную проблему. –

+0

Ничего себе, так просто: уникальная коробка внутри управляемой коробки, и она работает. Спасибо за помощь! –

Смежные вопросы