I trying to do some polymorphism with trait and object and I have some problems.

At the beginning I want to store different types of object that implement the same trait (Base) in a Vec. To do this I use the enum pattern. If the enum contains only struct, I manage to iter the Vec for the different types.
code:
enum BaseImpl    {
    FirstThinkImpl(FirstThink),
    SecondThinkImpl(SecondThink),
}

What I would like to do is to have a generic method to add like addMyBaseTrait( ~Base) to add all the struct that implement Base to the vector and to have a specific method that add a specific struct addSecondStruct(~SecondStruct). The enum is changed to:
enum BaseImpl    {
    FirstThinkImpl(~Base),
    SecondThinkImpl(~SecondThink),
}

With this enum has have problem to iter the vector. I didn't find a way to iter all the vector and return &Base or &~Base:
this code
impl<'a> Iterator<&'a ~Base> for BaseItems<'a> {
    fn next(&mut self) -> Option<&'a ~Base>    {
        match self.iter.next() {
            Some(ref baseimpl) => {
                Some(match ***baseimpl{
                    FirstThinkImpl(ref first) => first,
                    SecondThinkImpl(ref second)=> &'a (*second as ~Base),
                })
            },
            None => None,
        }
    }
}
generate an error borrowed value does not live long enough SecondThinkImpl(ref second)=> &'a (*second as ~Base), which is logic so I try not to borrow with this code:

SecondThinkImpl(ref second)=> second as &'a ~Base,

and I have the error non-scalar cast: `&~SecondThink` as `&'a ~Base<no-bounds>`
Perhaps there is no way. I didn't find any.
What I see with all my test is that a trait must be use as a reference to be stored but object reference can't be cast to a reference trait and trait can't be cast to an object. So it seems that tray is useful to pass or return parameters to method but not to store data.

Philippe


Le 09/04/2014 21:53, Philippe Delrieu a écrit :
I find a solution by removing the ~ to Base trait.
The code

//(First and Second think as defined earlier)


enum BaseImpl    {
    FirstThinkImpl(FirstThink),
    SecondThinkImpl(SecondThink),
}


struct Container    {
    nodeList: Vec<~BaseImpl>,
}

impl<'a> Container    {

    fn iter_base(&'a self) -> BaseItems<'a> {
           let iter = self.nodeList.iter();
           BaseItems{ iter : iter }
    }

}


struct BaseItems<'a> {
    iter : Items<'a, ~BaseImpl>
}

impl<'a> Iterator<&'a Base> for BaseItems<'a> {
    fn next(&mut self) -> Option<&'a Base>    {
        match self.iter.next() {
            Some(ref baseimpl) => {
                Some(match ***baseimpl{
                    FirstThinkImpl(ref first) => first as &'a Base,
                    SecondThinkImpl(ref second)=> second as &'a Base,
                })
            },
            None => None,
        }
    }
}

Now it compile.

So I try to define a mutable iterator like the immuable and with similar code I have again the lifetime compile error :


struct BaseMutItems<'a> {
    iter : MutItems<'a, ~BaseImpl>
}

impl<'a> Iterator<&'a mut Base> for BaseMutItems<'a> {
    fn next(&mut self) -> Option<&'a mut Base> {
        match self.iter.next() {
            Some(ref mut baseimpl) => {
                Some(match ***baseimpl{
FirstThinkImpl(ref mut first) => first as &'a mut Base, SecondThinkImpl(ref mut second)=> second as &'a mut Base,
                })
            },
            None => None,
        }
    }
}

error :
test_enum.rs:125:36: 125:49 error: lifetime of `baseimpl` is too short to guarantee its contents can be safely reborrowed test_enum.rs:125 FirstThinkImpl(ref mut first) => first as &'a mut Base,

I can't see what's going wrong.


I put all the code if someone want to test :

use std::iter::Iterator;
use std::slice::{Items, MutItems};

trait Base    {
  fn set_something(&mut self);
  fn isSecondThink(&self) -> bool;
}

struct FirstThink{
    count1: int,
}

impl Base for FirstThink    {
fn set_something(&mut self) {println!("ici First count:{:?}", self.count1); self.count1+=1;}
    fn isSecondThink(&self) -> bool  {false}
}

struct SecondThink{
    count2: int,
}

impl Base for SecondThink    {
fn set_something(&mut self) {println!("ici Second count:{:?}", self.count2); self.count2+=1;}
    fn isSecondThink(&self) -> bool  {true}
}

enum BaseImpl    {
    FirstThinkImpl(FirstThink),
    SecondThinkImpl(SecondThink),
}

fn some_second_process(think: &mut SecondThink)    {
    think.set_something();
}

struct Container    {
    nodeList: Vec<~BaseImpl>,
}

impl<'a> Container    {
    fn add_FirstThink(&mut self, think: FirstThink)    {
        self.nodeList.push(~FirstThinkImpl(think));
    }
    fn add_SecondThink(&mut self, think: SecondThink)    {
        self.nodeList.push(~SecondThinkImpl(think));
    }


    fn iter_base(&'a self) -> BaseItems<'a> {
           let iter = self.nodeList.iter();
           BaseItems{ iter : iter }
    }

    fn iter_second(&'a self) -> SecondItems<'a> {
           let iter = self.nodeList.iter();
           SecondItems{ iter : iter }
    }

    fn mut_iter_base(&'a mut self) -> BaseMutItems<'a> {
           let iter = self.nodeList.mut_iter();
           BaseMutItems{ iter : iter }
    }

fn appli_secondthink_someprocess(&mut self, fct : fn (&mut SecondThink)) {
        for think in self.nodeList.mut_iter() {
            match **think {
                FirstThinkImpl(first) => println!(""),
                SecondThinkImpl(ref mut second)=> fct(second),
            }
        }

    }

}

struct BaseItems<'a> {
    iter : Items<'a, ~BaseImpl>
}

impl<'a> Iterator<&'a Base> for BaseItems<'a> {
    fn next(&mut self) -> Option<&'a Base>    {
        match self.iter.next() {
            Some(ref baseimpl) => {
                Some(match ***baseimpl{
                    FirstThinkImpl(ref first) => first as &'a Base,
                    SecondThinkImpl(ref second)=> second as &'a Base,
                })
            },
            None => None,
        }
    }
}


struct SecondItems<'a> {
    iter : Items<'a, ~BaseImpl>
}

impl<'a> Iterator<&'a SecondThink> for SecondItems<'a> {
    fn next(&mut self) -> Option<&'a SecondThink>    {
        match self.iter.next() {
            Some(ref baseimpl) => {
                match ***baseimpl{
                    FirstThinkImpl(ref first) => self.next(),
                    SecondThinkImpl(ref second)=> Some(second),
                }
            },
            None => None,
        }
    }
}


struct BaseMutItems<'a> {
    iter : MutItems<'a, ~BaseImpl>
}

impl<'a> Iterator<&'a mut Base> for BaseMutItems<'a> {
    fn next(&mut self) -> Option<&'a mut Base> {
        match self.iter.next() {
            Some(ref mut baseimpl) => {
                Some(match ***baseimpl{
FirstThinkImpl(ref mut first) => first as &'a mut Base, SecondThinkImpl(ref mut second)=> second as &'a mut Base,
                })
            },
            None => None,
        }
    }
}



#[main]
fn main() {
    let first = FirstThink{count1:0};
    let second = SecondThink{count2:0};

    let mut container = Container{nodeList: Vec::new()};
    container.add_FirstThink(first);
    container.add_SecondThink(second);
    container.appli_secondthink_someprocess(some_second_process);
    container.appli_secondthink_someprocess(some_second_process);
    for think in container.iter_base()    {
        println!("ici Second count:{:?}", think.isSecondThink());
    }

    for think in container.iter_second()    {
        println!("ici Second count:{:?}", think.isSecondThink());
    }
    container.appli_secondthink_someprocess(some_second_process);
}

Le 07/04/2014 13:17, Philippe Delrieu a écrit :
I try to implement the iterator like that:


struct BaseItems<'a> {
    iter : Items<'a, ~BaseImpl>
}

impl<'a> Iterator<&'a ~Base> for BaseItems<'a> {
    fn next(&mut self) -> Option<&'a ~Base> {
        match self.iter.next() {
                Some(ref baseimpl) => {
                    Some(&'a match ***baseimpl{
                        FirstThinkImpl(ref first) => *first as ~Base,
                        SecondThinkImpl(ref second)=> *second as ~Base,
                    })
                },
                None => None,
        }
    }
}

But I have a lifetime problem. The error is : borrowed value does not live long enough and reference must be valid for the lifetime &'a as defined on the block
and :
cannot move out of dereference of `&`-pointer SecondThinkImpl(ref second)=> *second as ~Base,

Another possibility:
    fn next(&mut self) -> Option<&'a ~Base> {
        match self.iter.next() {
                Some(ref baseimpl) => {
                    Some(match ***baseimpl{
                        FirstThinkImpl(ref first) => first as &'a ~Base,
SecondThinkImpl(ref second)=> second as &'a ~Base,
                    })
                },
                None => None,
        }
    }
generate the error: non-scalar cast: `&~FirstThink` as `&'a ~Base<no-bounds>`

I try different possibility but I didn't find how to return a <'a> lifetime ~Base or Base

I remove the mut to simplify the test of the different lifetime possibilities.

Philippe

Le 07/04/2014 10:27, Rodrigo Rivas a écrit :
On Sun, Apr 6, 2014 at 7:50 PM, Philippe Delrieu
<[email protected]> wrote:
I need some more help.

The impl Iterator<&mut ~Base> for Container declaration generate the error:
error: missing lifetime specifier
So I had it but I can't manage to return the next value with the specified
life time.
The code :
impl<'a> Iterator<&'a mut  ~Base> for Container {
/// Advance the iterator and return the next value. Return `None` when
the end is reached.
     fn next(&mut self) -> Option<&'a mut ~Base>    {
         if self.iter_counter == self.nodeList.len()   {
             None
         } else  {
             self.iter_counter += 1;
Some(&'a mut match **self.nodeList.get(self.iter_counter){
                 FirstThinkImpl(first) => first as ~Base,
                 SecondThinkImpl(second)=> second as ~Base,
             })
         }
     }
}

Generate these errors :
test_enum.rs:58:18: 61:14 error: borrowed value does not live long enough
test/test_enum.rs:58             Some(&'a mut match
Oh, I think I may have misleaded you... You cannot implement the
iterator directly in Container, because the iterator must handle the
current position, while the Container just holds the values. You need
a intermediate struct that implements the Iterator traits. That's what
the `iter()` and ' move_iter()` functions do for vectors and other
standard containers. So you'll need something along the lines of this
(disclaimer: totally untested!!):

struct Container {
     //....
     fn iter(&'a self) -> BaseItems<'a> {
            let iter = nodeList.iter();
            BaseItems{ iter : iter }
     }
}

struct BaseItems<'a> {
     iter : Items<'a, ~Base>
}

impl<'a> Iterator<&'a mut  ~Base> for BaseItems<'a> {
     //....
}

BTW, why all the double pointer in all the "&mut ~Base" instead of
just "&mut Base"?


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



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



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

Reply via email to