3

What I want to do:

I want to create a small parser in rust that can decode several types -> numbers, strings, lists, etc. For instance the lists can contain any type -> other lists, numbers, etc

How I'm trying to do it:

I have a super trait 'Element' which will be the base for all my types. Then I have a a trait per type, which all require the 'Element' trait. Those traits are backed by some concrete structs. Because the lists can contain (mixed) any type, I try to store the values as Vec<Box<dyn Element>>. The issue is that when later I try to convert the dyn Element to another trait, I hit a wall:

The error:

error[E0161]: cannot move a value of type dyn Element: the size of dyn Element cannot be statically determined
  --> src/main.rs:94:27
   |
94 |     let boxed_as_number = num_as_element.to_boxed_number();
   |                           ^^^^^^^^^^^^^^

MCVE

use std::fmt;

pub enum ElementType {
    Number,
    Text,
}

pub trait Element: fmt::Debug {
    fn element_type(&self) -> ElementType;

    // Works, but I do not want a reference -> I want to change the "type"
    fn to_number_ref(&self) -> Option<&dyn Number>;

    fn to_boxed_number(self) -> Option<Box<dyn Number>>;
}

pub trait Number: Element {
    fn value(&self) -> i64;
}

pub trait Text: Element {
    fn value(&self) -> &str;
}

#[derive(Debug)]
pub struct SignedNumber {
    value: i64
}

impl SignedNumber {
    fn new(value: i64) -> SignedNumber {
        return SignedNumber { value };
    }
}

impl Element for SignedNumber {
    fn element_type(&self) -> ElementType {
        return ElementType::Number;
    }

    fn to_number_ref(&self) -> Option<&dyn Number> {
        return Some(self);
    }

    fn to_boxed_number(self) -> Option<Box<Number>> {
        return Some(Box::new(self));
    }
}

impl Number for SignedNumber {
    fn value(&self) -> i64 {
        return self.value;
    }
}

#[derive(Debug)]
pub struct StringWrapper {
    value: String
}

impl StringWrapper {
    fn new<T: Into<String>>(value: T) -> StringWrapper {
        return StringWrapper { value: value.into() };
    }
}

impl Element for StringWrapper {
    fn element_type(&self) -> ElementType {
        return ElementType::Text;
    }

    fn to_number_ref(&self) -> Option<&dyn Number> {
        return None;
    }

    fn to_boxed_number(self) -> Option<Box<Number>> {
       return None;
    }
}

impl Text for StringWrapper {
    fn value(&self) -> &str {
        return &self.value;
    }
}

fn main() {
    let num = SignedNumber::new(1);
    let num_as_element: Box<dyn Element> = Box::new(num);
    let borrowed_as_num = num_as_element.to_number_ref().unwrap();

    let num = SignedNumber::new(2);
    let num_as_element: Box<dyn Element> = Box::new(num);
    let boxed_as_number = num_as_element.to_boxed_number();
}

Why

Shouldn't self be SignedNumber in that case ? Why does rustc thinks it's dyn Element ?

impl Element for SignedNumber {
    fn to_boxed_number(self) -> Option<Box<Number>> {
        return Some(Box::new(self));
    }
}

Is there a way to do such type conversion or should I stick with references ?

Boiethios
  • 38,438
  • 19
  • 134
  • 183
Svetlin Zarev
  • 14,713
  • 4
  • 53
  • 82

0 Answers0