Generic arithmetic with std::ops::Add?


#1

Hi,

Hi, i am totally new to Rust, coming from a background in C# Java and C++. I find many of Rusts concepts quite innovative, but i am also having some trouble getting them working, so i was hoping i could find a little bit of help here.

So, this is probably a really stupid question, but i would like to understand why the following isn’t valid (which is something i cannot do in C# and its been annoying me for a while):

use std::ops::Add;

fn foo<T:Add>(x : T) -> T{
    return x + x;
}

fn main() {
    foo(42);
}

It produces a “mismatched types” error.


#2

The result type of an addition is not necessarily the same type as the operands.

For that reason, there’s an associated type called Output in the Add trait that denotes the output or result type.
You have to use that type as return type of your function.


#3

You can also require matching output up front with T:Add<Output=T>.

But note that x + x is also a problem, because you’re moving the same x by value in two places. This is fine if you also require T:Copy, or else you can require T:Clone and use x.clone() + x.

Or you can add by reference, something like:

fn foo<'a, T>(x: &'a T) -> T
where &'a T: Add<&'a T, Output=T>
{
    x + x
}

#4

You can write:

use std::ops::Add;

fn double_it<T>(x: T) -> T
where T: Add<Output=T> + Copy + Clone {
    x + x
}

fn main() {
    println!("{}", double_it(21));
}

#5

Thanks for all the replies, good to see Rust has a friendly community. It makes sense that it needs Copy, though the syntax for setting Output from Add is a bit surprising :slight_smile: Really nice to be able to do this, i cannot do it in either F# or C#.


#6

Thank you.


#7

I got an adjunct question here… How can I do the same but instead of:

x + x in the body, I want x + 2 for an “add_two” function.

For this, Rust complains that I’m returning a type of {integer} rather than T. So the math op is apparently converting the result to {integer} and thus now it’s not compatible with the return type of T. I also tried with ret type of Output but since that ins’t {integer} it still doesn’t work obviously… I’m wondering if I need to do something like 2.convert_to_T? That doesn’t seem quite right though.

I wanted my func to work with anything that implements Add:

fn add_two<T: Add<Output=T>>(num: T) -> T
{
    num + 2
}

#8

You’d want T: Add<i32, Output=T> - you need to indicate that T can add i32 to itself.

Alternatively, you can say that T can be converted from i32:

fn add_two<T: Add<Output=T> + From<i32>>(num: T) -> T { 
     num + 2.into() 
}