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