In a Rust project I have I would like to be able to store arbitrary types in a matrix (similar to e.g. a python list of lists), and then sort the matrix by columns in different ways. I realise this is difficult to do in a completely generic way in Rust, so I'm trying to work around the problem.
One approach I have is to store the "rows" as a struct with fields according to what types I want, and then store them in a Vector. Then, when addressing the different "columns" of the data (e.g. the same field across each struct in the vec), I would like to use a "column-index" (0 for field 0, 1 for field 1 etc), to avoid having to reference them by their field-name. This works fine if the types of the structs fields are the same, but doesn't work if I use a generic type-parameter as return type. The ultimate goal with this approach is to write a proc_macro which adds this to an arbitrary "basic" struct (e.g. only containing "basic types"), so hard-coding it for each struct is something I would like to avoid. I have the proc_macro code producing the same get_column-implementation below so that is not an issue. The issue is to get the get_column to work.
Questions:
1/ Is there an other more preferable way of storing a generic matrix-like data-structure with columns of different types?
2/ If not, is there a work-around solution to create my get_column-function for a generic data type (see my MWE below)?
3/ Perhaps another approach is to wrap the row-elements in a Box or something similar? (I did not include the Box-idea code here, but did not get it to work in a generic way either...)
Below is my attempt as a MWE:
// This works, but is not generic enough
#[derive(Debug, Clone)]
struct A { x: i64, y: i64 } // struct has several fields, but all with the same type
impl A {
fn get_column(&self, column: usize) -> Result<i64, String> { // return type is obvious so it can be hardcoded...
if column == 0 { return Ok(self.x.clone()) }
else if column == 1 { return Ok(self.y.clone()) }
else { return Err("Invalid column number.".to_string()) };
}
}
fn main() {
let a: A = A {x: 3, y: 2};
let val_a = a.get_column(0);
}
/* ********************************************** */
// This generic approach doesn't work
// Produces the error "expected type parameter `T`, found `u64`",
// which is odd to me since it then looks like the compiler actually knows the type
// and shouldnt complain at all...?
#[derive(Debug, Clone)]
struct B { x: i64, y: u64 } // fields have different types
impl B {
// get_column has generic type T.
fn get_column<T: Clone>(&self, column: usize) -> Result<T, String> {
if column == 0 { return Ok(self.x.clone()) }
// etc for other fields...