I'm trying to model a dataframe-like structure. I know how use enum
s here, but I'm exploring how do it similar to C#/Python/etc.
I tried to follow Rust Trait object conversion but things are not working:
use std::any::{Any};
use std::fmt::Debug;
pub trait Value: Any + Sized {
fn as_any(&self) -> &Any {
self
}
fn as_any_mut(&mut self) -> &mut Any {
self
}
}
impl Value for i32 {}
#[derive(Debug)]
struct Frame {
data: Vec<Box<Any>>,
}
fn make_int(of: Vec<i32>) -> Frame {
let data = of.into_iter().map(|x| Box::new(x.as_any())).collect();
Frame {
data: data,
}
}
The compiler complains:
error[E0277]: the trait bound `std::vec::Vec<std::boxed::Box<std::any::Any>>: std::iter::FromIterator<std::boxed::Box<&std::any::Any>>` is not satisfied
--> src/main.rs:40:61
|
40 | let data = of.into_iter().map(|x| Box::new(x.as_any())).collect();
| ^^^^^^^ a collection of type `std::vec::Vec<std::boxed::Box<std::any::Any>>` cannot be built from an iterator over elements of type `std::boxed::Box<&std::any::Any>`
|
= help: the trait `std::iter::FromIterator<std::boxed::Box<&std::any::Any>>` is not implemented for `std::vec::Vec<std::boxed::Box<std::any::Any>>`
The main problem is with this function:
fn as_any(&self) -> &Any {
self
}
This means that you can borrow a Value
as a &Any
, (it converts a &Value
into a &Any
).
But then, you want to create a Box<Any>
from that &Any
. That will never work, because &Any
is a borrowed value, while Box<Any>
is owned.
The easiest solution would be to change the trait to return the boxed value (an owned trait object):
pub trait Value: Any + Sized {
fn as_boxed_any(&self) -> Box<Any> {
Box::new(self)
}
//The mut variation is not needed
}
Now the make_int
function is trivial:
fn make_int(of: Vec<i32>) -> Frame {
let data = of.into_iter().map(|x| x.as_boxed_any()).collect();
Frame {
data: data,
}
}
UPDATE: Tinkering a bit, I've found that you can create the Vec<Box<Any>>
by writing:
fn make_int(of: Vec<i32>) -> Frame {
let data = of.into_iter().map(|x| Box::new(x) as Box<Any>).collect();
Frame {
data: data,
}
}
If you are writing the trait only for this conversion, you don't actually need it.