简体   繁体   中英

How can I create a generic function that returns a modified instance of the generic type?

I have a number of generic functions that need to return new instances of the generic. However, the fields in the generic are not known, but I need to get/set the field values to create the instance (a simple Default will not work). For primitive fields, I can update my struct, but for fields with Vector or HashMap types, I get the error:

the size for values of type `[usize]` cannot be known at compilation time

Here is a minimal working example of my issue:

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=6db1dd0b5982eca526725f4e5b423263

trait MyTrait {
    fn id(&self) -> &usize;
    fn id_mut(&mut self) -> &mut usize;

    fn data(&self) -> &[usize];
    fn data_mut(&mut self) -> &mut [usize];
}

#[derive(Debug)]
struct MyStruct {
    id: usize,
    data: Vec<usize>,
}

impl MyTrait for MyStruct {
    fn id(&self) -> &usize {
        &self.id
    }
    fn id_mut(&mut self) -> &mut usize {
        &mut self.id
    }
    fn data(&self) -> &[usize] {
        &self.data
    }
    fn data_mut(&mut self) -> &mut [usize] {
        &mut self.data
    }
}

impl Default for MyStruct {
    fn default() -> MyStruct {
        MyStruct {
            id: 0,
            data: vec![],
        }
    }
}

fn my_func<T: MyTrait + Default>() -> T {
    let mut d = T::default();
    // this correctly updates the struct field "id" to 26
    *d.id_mut() = 26;
    // this however, does not work. i get an error:
    // the size for values of type `[usize]` cannot be known at compilation time
    *d.data_mut() = vec![1, 2, 3].as_slice();
    d
}

fn main() {
    let _my_instance = my_func::<MyStruct>();
}

How can I create a generic function that returns an instance of the generic type?

For your Default instance of MyStruct , data is an empty Vec , but you are exposing it as a mutable slice. This is pretty meaningless because you can't change the length of a mutable slice; you can only mutate existing elements.

You will need to expose data as a &mut Vec<usize> instead, so that you can insert elements. The immutable getter can stay the same.

trait MyTrait {
    fn id(&self) -> &usize;
    fn id_mut(&mut self) -> &mut usize;

    fn data(&self) -> &[usize];
    fn data_mut(&mut self) -> &mut Vec<usize>;
}

And change the code that updates it:

fn my_func<T: MyTrait + Default>() -> T {
    let mut d = T::default();
    *d.id_mut() = 26;
    *d.data_mut() = vec![1, 2, 3];
    d
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM