2013-05-24 6 views
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) }); 
} 

나는() 핸들러 간단한 관리 클로저를 전달하고 그들을 @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

공유 상자는, 고유하지 않은 관리해야합니다

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

와우, 너무 간단 : 관리 상자 안에있는 고유 한 상자가 작동합니다. 도와 주셔서 감사합니다! –