Hello,

I've updated my sample code to reflect what I'll do in my main program. I put it back on the list because it can help as a pattern to manage a tree of polymorph object.
It compile and works.
I have some question too because I'm not sure I've done it the right way:
* I cross the tree recursively and return Option in each call. To manage recursion I put the call in a match and end with this sort of boilerplate code:
        match obj.call_fn_recusive()    {
            Some(ret) => {return Some(ret);},
            None => {},
        }
Is there a way to avoid this line: Some(ret) => {return Some(ret);}, * It's very hard to manage reference and borrowing of object. I spend some time to make it compile and change my algorithm several time. That's why I think examples and patterns can be very useful because you can't do what you want in rust. In other works there is no easy shortcut, you have to find the right way. * closure indentation. Is there a good way to indent closure in function call to make it readable easily. It's very hard to find the begin/end of the closure code from the function and match call (see code).

Some world about the pattern :
I use an enum to define a type that manage all my polymorph object (enum UINode). It's the simplest way I found to have a collection a different objects that implement part of the same trait. I don't want to use unsafe code and low memory management. Perhaps there is a better pattern. The object can only be retrieve or modified with search function that use a closure to do the job. It's work well to avoid to know how the tree is organized and to avoid object reference outside the tree. The mutable part is restricted to one function too.

The code:

use std::vec::Vec;

pub enum UINode {
    DrawableNode(Inside),
    ContainerNode(ListInside),
}

//common trait for all object
trait Component {
    fn get_width(&self) -> uint;
    fn get_id(&self) -> uint;
}

//first struct. derive clone because it can be return as a copy.
//base component.
#[deriving(Clone)]
pub struct Inside {
    id: uint,
    width: uint,
}

impl Component for Inside{
    fn get_id(&self) -> uint {self.id}
    fn get_width(&self) -> uint {
        self.width
    }
}

//the container that is a component and a container of components.
pub struct ListInside   {
    id: uint,
    width: uint,
    list: Vec<~UINode>,
}


impl Component for ListInside{
    fn get_id(&self) -> uint {self.id}
    fn get_width(&self)  -> uint  {
        self.width
    }
}

//some container function and the search and modify function.
impl ListInside {
    fn addInside(&mut self, inside: Inside)   {
        self.list.push(~DrawableNode(inside));
    }

    fn addList(&mut self, list: ListInside)   {
        self.list.push(~ContainerNode(list));
    }

// search for a UINode using the closure filter to find the right. Return the node Id. fn match_fn<'a>(&'a self, filter: &'a |&'a UINode| -> Option<uint>) ->Option<uint> {
        for inside in self.list.iter()    {
            match (*filter)(*inside)    {
                Some(found) => return Some(found),
                None => {},
            };
            //try on sub tree
            match **inside    {
                DrawableNode(_) => {},
                ContainerNode(ref list_inside) => {
                    match list_inside.match_fn(filter)  {
                        Some(ret) => {return Some(ret);}
                        None => {}
                    }
                },
            }
        }
        None
    }

    //modify using the specified closure the Component with specified id.
fn test_mutable<'a>(&'a mut self, id: uint, update: &'a|&'a mut Inside|) {
        for node in self.list.mut_iter()   {
            match **node    {
DrawableNode(ref mut inside) => {if inside.get_id() == id {(*update)(inside)}}, ContainerNode(ref mut list_inside) => list_inside.test_mutable(id, update),
            }
        }
    }

//return a copy of the Component with specified id. Doesn't return container, only Inside.
    fn search_node<'a>(&'a self, id: uint) -> Option<~Component> {
        for node in self.list.iter()   {
            match **node    {
DrawableNode(ref inside) => if inside.get_id() == id { return Some((~inside.clone()) as ~Component);}, ContainerNode(ref list_inside) => { match list_inside.search_node(id) {
                    Some(elem) => {return Some(elem);},
                    None => {},
                }},
            }
        }
        None
    }
}

fn TestTreeSearchModify()    {
    let mut list_inside = ListInside{
        id: 0,
        width: 10,
        list: Vec::new(),
    };

    let mut list2 = ListInside{
        id: 3,
        width: 30,
        list: Vec::new(),
    };

    let inside1 = Inside {
        id: 1,
        width: 21,
    };

    let inside2 = Inside {
        id: 2,
        width: 22,
    };

    list_inside.addInside(inside1);
    list2.addInside(inside2);
    list_inside.addList(list2);

    let search_id = 2;
    let new_width:uint = 122u;

    match list_inside.match_fn(&|inside: &UINode| -> Option<uint>  {
        println!("Inside match closure node:{:?}", inside);
        match *inside    { //search for id 2;
DrawableNode(ref inside) => if inside.get_id() == search_id { return Some(inside.get_id());}, ContainerNode(ref list_inside) => if list_inside.get_id() == search_id { return Some(list_inside.get_id());},
        }
        None

    })  {
        Some(found_id) => {
            match list_inside.search_node(found_id)   {
Some(compo) => println!("Found component with id {0} and width {1}", compo.get_id(), compo.get_width()),
                None => {println!("Search_node deosn't work first");}
            };
            list_inside.test_mutable(found_id, &|component: &mut Inside| {
                component.width = new_width;
            });
            match list_inside.search_node(found_id)   {
Some(compo) => println!("Found updated component with id {0} and width {1}", compo.get_id(), compo.get_width()),
                None => {println!("Search_node deosn't work bis");}
            };
        },
        None => {println!("Match_fn deosn't work first");},
    }
}

#[main]
fn main() {
    TestMatchBorrow();
}


Philippe
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to