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 ?