Using generic types in my functions

I just finished the section in The Book on dealing with generic types. So, I’ve been trying to get a handle on how to use generic types in my functions with an eye toward using them in some of the functions I keep in my personal function library. With that in mind, I decided to write a simple function to experiment with. Here’s the code:

fn main() {
let num1 = 7;
let more = add_three(&num1);

println!("{} + 3 = {}", num1, more);
}

fn add_three(value: &i32) -> i32 {
return value + 3
}

This code works just fine as long as I define the type (in this case i32).

So here’s what I came up with when I tried to convert it to using a generic type:

fn main() {
    let num1 = 7;
    let more = add_three(&num1);

    println!("{} + 3 = {}", num1, more);
}

fn add_three <T> (value: &T) -> T {
    return value + 3
}

This code doesn’t compile, instead returning the following error:

error[E0369]: cannot add `{integer}` to `&T`--> src/main.rs:13:18

13 |     return value + 3
|            ----- ^ - {integer}
|            |
|            &T
|
help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement

When I tried doing this in my Sublime editor, the suggestion came up that I use a where clause in the function return declaration. It looks like this:

fn add_three<T>(value: &T) -> T where &T: Add<i32>

but that just threw more errors at me that I haven’t been able to decipher. I’m thinking that the problem is that I’m trying to add an integer, 3, to what could be an incompatible type that depends on the type of the variable I pass to the function. I really don’t know what to do about that.

Anyone care to instruct me on how to make using generics work for me? Thanks.

The immediate error is:

 `&` without an explicit lifetime name cannot be used here

You can fix it by introducing an explicit lifetime parameter. Also you need to take into account the fact that the result of addition can have a type different from T. In general, the associated type Output on Add trait implementation indicates the output type. This works:

fn add_three<'a, T>(value: &'a T) -> <&'a T as Add<i32>>::Output
where
    &'a T: Add<i32>,
{
    return value + 3;
}
2 Likes

I'll note that using generics for arithmetic in Rust is often more trouble than it's worth because of all the trait bounds you need to add to your functions. You might find it more fruitful to play around with generic collections, like vectors and slices, while you're learning generics. Functions like this, for example:

fn count<T:Eq>(needle:&T, values:&[T])->u32 {
    let mut count = 0;
    for x in values {
        if x == needle { count += 1 }
    }
    count
}

fn main() {
    dbg!(count(&1, &[3,1,4,1,5,9]));
    dbg!(count(&'l', &['h','e','l','l','o']));
}
2 Likes

Numeric operations with generic types are often realized using the traits of the num crate. But it is kinda unergonomic. I remember I was pretty disappointed when I realized I either use complicated type bounds depending on non-std crates, or decide whether I make my functions work on f32 or f64 only. Not nice! But once you get used to num, it's not that bad.

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.