Home > database >  Make functions instantiate its generic parameter
Make functions instantiate its generic parameter

Time:05-06

What would be an equivalent to the following C program in rust?

#include <iostream>
#include <vector>

template <typename T>
T stuff() {
    return T();
}
int main() {
    std::vector<int> vec = stuff<std::vector<int>>();
    vec.push_back(1);
    for (auto &&i : vec) {
        std::cout << i << std::endl;
    }
}

I tried the following:

trait Newable{
    fn new() -> Self;
}
fn stuff<T: Newable>() -> T {
    T::new()
}

I tried using a newtype for this -

struct NwVec<T>{
    vec: Vec<T>
}
impl<T> Newable<T> for NwVec<T>{
    fn new() -> Self {
        NwVec { vec: Vec::new() }
    }
}

and used it like so:

fn main() {
    let x: NwVec<i32> = stuff::<NwVec<i32>>();
}

but I get a

error[E0277]: the trait bound `NwVec<i32>: Newable<NwVec<i32>>` is not satisfied
  --> src\main.rs:2:25
   |
2  |     let x: NwVec<i32> = stuff();
   |                         ^^^^^ the trait `Newable<NwVec<i32>>` is not implemented for `NwVec<i32>`
   |
   = help: the following implementations were found:
             <NwVec<T> as Newable<T>>
note: required by a bound in `stuff`

Is there a way to achieve what the C program achieves?

P.S.: I am rather new to rust, I am really sorry if the solution to this is trivial.

CodePudding user response:

Maybe there was a mixup when you entered the code that you say gave you the error you provided, because that same code did not yield that specific error when I tried it.

Either way, you were close. Consider this code:

trait Newable {
    fn new() -> Self;
}

fn stuff<T: Newable>() -> T {
    T::new()
}

#[derive(Debug)]
struct NwVec<T> {
    vec: Vec<T>
}

impl<T> Newable for NwVec<T> {
    fn new() -> Self {
        NwVec { vec: Vec::new() }
    }
}

fn main() {
    let x: NwVec<i32> = stuff::<NwVec<i32>>();
    
    println!("{x:?}");
}

Playground

All I changed was:

  • Added #[derive(Debug)] to NwVec<T> so we could print it out
  • I removed the type parameter <T> on Newable<T> from your original impl<T> Newable<T> for NwVec<T>. This is because the Newable trait itself, as provided in your post, is not generic, so it takes no type parameter.

I imagine this is something of a learning exercise, but in case you were curious, you may be interested in std::default::Default which is a trait somewhat similar to your Newable in that implementations provide a simple and consistent way to create a "default" version of something. Vec itself is an implementer, so you can call e.g. Default::default() or Vec::default() wherever a Vec<T> is expected. Check this playground.

CodePudding user response:

Adding to the excellent answer by @JorgeIsraelPeña, in case you insist on Newable, you don't need a newtype. You can implement a trait for a type as long as either the trait or the type are yours (well, the actual rules are a bit more complicated). That means you can implement Newable directly for Vec:

impl<T> Newable for Vec<T> {
    fn new() -> Self {
        Vec::new()
    }
}

fn main() {
    let x = stuff::<Vec<i32>>();

    println!("{x:?}");
}

Playground.

  • Related