Using a generic vector from within a struct

I need to include a vector as a field of a struct. The vector could be full of either i64, u64, f64, or Strings, depending on user choices. So, I tried to set up my struct to take a generic type, and, of course, it doesn't work. Here's my first attempt (using a vector filled with strings to test the code):

Struct Corral<T> {
    list_vec: Vec<T>,
}

impl Corral {
    new() -> Corral <T> {
        Self {
            list_vec: Vec<T>,
        }
    }
}

fn main() {
    mut feedlot = Corral::new();
    feedlot.list_vec = vec!["hereford", "angus", "shorthorn","hybrid"];
    println!("\n\n The lot contains:   {:?}", feedlot.list_vec);
} 

I am clumsy at best when it comes to generics, but if there is a way to make this work with generics I want to use it. The alternative is to do a separate vector field for each possible type, which seems unwieldy to me. Any ideas? Thanks.

You need to add the generic parameter to the impl block as well. Besides that there are a few syntactical errors in your snippet, but the main problem is that you forgot to add T to the impl block like impl<T> Corral<T> {:

struct Corral<T> {
    list_vec: Vec<T>,
}

impl<T> Corral<T> {
    fn new() -> Corral <T> {
        Self {
            list_vec: Vec::new(),
        }
    }
}

fn main() {
    let mut feedlot = Corral::new();
    feedlot.list_vec = vec!["hereford", "angus", "shorthorn","hybrid"];
    println!("\n\n The lot contains:   {:?}", feedlot.list_vec);
} 

Playground.

1 Like

Your code was mixing up types and values. Vec<T> is a type, not a value so you can't pass it as the value of list_vec inside new. You need to create a value with that type instead, which Vec::new() can do.

You can also simplify things a bit in your new method by using the Self return type

impl<T> Corral<T> {
    fn new() -> Self {
        Self {
            list_vec: Vec::new(),
        }
    }
}

Additionally if you're just going to set the list_vec field after calling new, you could just make it a parameter to the new function.

struct Corral<T> {
    list_vec: Vec<T>,
}

impl<T> Corral<T> {
    fn new(list_vec: Vec<T>) -> Self {
        Self { list_vec }
    }
}

fn main() {
    let mut feedlot = Corral::new(vec!["hereford", "angus", "shorthorn", "hybrid"]);
    println!("\n\n The lot contains:   {:?}", feedlot.list_vec);
}
4 Likes

Boy, no kidding. Not sure why other than I suppose I was so focused on the generic stuff that I got careless with the rest. Your fixes worked. Thanks!

I like that. Passing the vector as a parameter does simplify some things. We'll see how it works, but I may incorporate that into the actual application. Thanks.

Keep in mind that both blessing and a curse of Rust's generics lies with the fact that you need to describe all constraints explicitly. E.g. you Corral may be printed with print for all types you need: i64, u64, f64, or String. Does it mean that may just write function show like this:

    fn show(&self) {
        println!("\n\n The lot contains:   {:?}", self.list_vec);
    }

Nope, does't work. You need to tell compiler that you only plan to use that with types that would be printable, like this:

    fn show(&self) where T: Debug {
        println!("\n\n The lot contains:   {:?}", self.list_vec);
    }

This makes generics easier to use then generics in other languages (like C++ or Zig) but also harder to write.

Sometimes, when you see that you drown in these constraints you may decide to just use macros to generate implementation for a few fixed types that you need.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.